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

Revision 2560, 183.5 KB checked in by mattausch, 17 years ago (diff)

added functionality for visualization

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#include "Timer/PerfTimer.h"
27
28
29#define USE_RAY_LENGTH_AS_CONTRIBUTION 0
30#define DIST_WEIGHTED_CONTRIBUTION 0
31#define SUM_RAY_CONTRIBUTIONS 1
32#define AVG_RAY_CONTRIBUTIONS 0
33#define CONTRIBUTION_RELATIVE_TO_PVS_SIZE 0
34#define PVS_ADD_DIRTY 1
35
36
37
38namespace GtpVisibilityPreprocessor {
39
40
41PerfTimer viewCellCastTimer;
42PerfTimer pvsTimer;
43PerfTimer objTimer;
44
45// HACK
46const static bool SAMPLE_AFTER_SUBDIVISION = true;
47//const static bool CLAMP_TO_BOX = false;
48const static bool CLAMP_TO_BOX = true;
49
50
51
52inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
53{
54        return obj1->mId < obj2->mId;
55}
56
57
58template <typename T> class myless
59{
60public:
61        //bool operator() (HierarchyNode *v1, HierarchyNode *v2) const
62        bool operator() (T v1, T v2) const
63        {
64                return (v1->GetMergeCost() < v2->GetMergeCost());
65        }
66};
67
68
69ViewCellsManager::ViewCellsManager(ViewCellsTree *viewCellsTree):
70mRenderer(NULL),
71mInitialSamples(0),
72mConstructionSamples(0),
73mPostProcessSamples(0),
74mVisualizationSamples(0),
75mTotalAreaValid(false),
76mTotalArea(0.0f),
77mViewCellsFinished(false),
78mMaxPvsSize(9999999),
79mMinPvsSize(0),
80mMaxPvsRatio(1.0),
81mViewCellPvsIsUpdated(false),
82mPreprocessor(NULL),
83mViewCellsTree(viewCellsTree),
84mUsePredefinedViewCells(false),
85mMixtureDistribution(NULL),
86mEvaluationSamples(0)
87{
88        mViewSpaceBox.Initialize();
89        ParseEnvironment();
90
91        mViewCellsTree->SetViewCellsManager(this);
92        mSamplesStat.Reset();
93        mStats.open("mystats.log");
94}
95
96
97int ViewCellsManager::CastEvaluationSamples(const int samplesPerPass,
98                                                                                        VssRayContainer &passSamples)
99{
100        static int pass = 0;
101        static int totalRays = 0;
102
103        SimpleRayContainer rays;
104        rays.reserve(samplesPerPass);
105        //passSamples.reserve(samplesPerPass * 2);
106 
107        long startTime = GetTime();
108
109        cout<<"Progress :"<<totalRays / 1e6f << " M rays, " << (100.0f * totalRays) / (mEvaluationSamples + 1) << "%" << endl;
110       
111        //rays.clear();
112        //passSamples.clear();
113       
114        mMixtureDistribution->GenerateSamples(samplesPerPass, rays);
115       
116        const bool doubleRays = true;
117        const bool pruneInvalidRays = true;
118        mPreprocessor->CastRays(rays, passSamples, doubleRays, pruneInvalidRays);
119
120        mMixtureDistribution->ComputeContributions(passSamples);
121        mMixtureDistribution->UpdateDistributions(passSamples);
122       
123        Real time = TimeDiff(startTime, GetTime());
124        PrintPvsStatistics(mStats);
125       
126        mStats <<
127                "#Pass\n" << pass ++ <<endl<<
128                "#Time\n" << time <<endl<<
129                "#TotalSamples\n" << totalRays << endl;
130       
131
132        totalRays += samplesPerPass;
133
134        return (int)passSamples.size();
135}
136
137
138void ViewCellsManager::ParseEnvironment()
139{
140        // visualization stuff
141        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportRays", mExportRays);
142        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportGeometry", mExportGeometry);
143        Environment::GetSingleton()->GetFloatValue("ViewCells.maxPvsRatio", mMaxPvsRatio);
144       
145        Environment::GetSingleton()->GetBoolValue("ViewCells.processOnlyValidViewCells", mOnlyValidViewCells);
146
147        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samples", mConstructionSamples);
148        Environment::GetSingleton()->GetIntValue("ViewCells.PostProcess.samples", mPostProcessSamples);
149        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.useRaysForMerge", mUseRaysForMerge);
150
151        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.samples", mVisualizationSamples);
152
153        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samplesPerPass", mSamplesPerPass);
154        Environment::GetSingleton()->GetBoolValue("ViewCells.exportToFile", mExportViewCells);
155       
156        Environment::GetSingleton()->GetIntValue("ViewCells.active", mNumActiveViewCells);
157        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.compress", mCompressViewCells);
158        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.useClipPlane", mUseClipPlaneForViz);
159        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.merge", mMergeViewCells);
160        Environment::GetSingleton()->GetBoolValue("ViewCells.evaluateViewCells", mEvaluateViewCells);
161        Environment::GetSingleton()->GetBoolValue("ViewCells.showVisualization", mShowVisualization);
162        Environment::GetSingleton()->GetIntValue("ViewCells.Filter.maxSize", mMaxFilterSize);
163        Environment::GetSingleton()->GetFloatValue("ViewCells.Filter.width", mFilterWidth);
164
165        Environment::GetSingleton()->GetBoolValue("ViewCells.exportBboxesForPvs", mExportBboxesForPvs);
166        Environment::GetSingleton()->GetBoolValue("ViewCells.exportPvs", mExportPvs);
167
168        Environment::GetSingleton()->GetBoolValue("ViewCells.useKdPvs", mUseKdPvs);
169
170        char buf[100];
171        Environment::GetSingleton()->GetStringValue("ViewCells.samplingType", buf);
172
173        Environment::GetSingleton()->GetFloatValue("ViewCells.triangleWeight", mTriangleWeight);
174        Environment::GetSingleton()->GetFloatValue("ViewCells.objectWeight", mObjectWeight);
175
176        // choose mix of sampling strategies
177        if (0)
178        {
179                mStrategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
180                //mStrategies.push_back(SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION);
181        }
182        else
183        {
184                //mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
185
186                mStrategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
187                mStrategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
188                       
189                mStrategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
190        }
191               
192    Debug << "casting strategies: ";
193        for (int i = 0; i < (int)mStrategies.size(); ++ i)
194                Debug << mStrategies[i] << " ";
195        Debug << endl;
196
197        // sampling type for view cells construction samples
198        if (strcmp(buf, "object") == 0)
199        {
200                mSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
201        }
202        else if (strcmp(buf, "box") == 0)
203        {
204                mSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
205        }
206        else if (strcmp(buf, "directional") == 0)
207        {
208                mSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
209        }
210        else if (strcmp(buf, "object_directional") == 0)
211        {
212                mSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
213        }
214        else if (strcmp(buf, "reverse_object") == 0)
215        {
216                mSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
217        }
218        /*else if (strcmp(buf, "interior") == 0)
219        {
220                mSamplingType = Preprocessor::OBJECTS_INTERIOR_DISTRIBUTION;
221        }*/
222        else
223        {
224                Debug << "error! wrong sampling type" << endl;
225                exit(0);
226        }
227
228        // sampling type for evaluation samples
229        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.samplingType", buf);
230       
231        if (strcmp(buf, "object") == 0)
232        {
233                mEvaluationSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
234        }
235        else if (strcmp(buf, "box") == 0)
236        {
237                mEvaluationSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
238        }
239        else if (strcmp(buf, "directional") == 0)
240        {
241                mEvaluationSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
242        }
243        else if (strcmp(buf, "object_directional") == 0)
244        {
245                mEvaluationSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
246        }
247        else if (strcmp(buf, "reverse_object") == 0)
248        {
249                mEvaluationSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
250        }
251        else
252        {
253                mEvaluationSamplingType = -1;
254                Debug << "error! wrong sampling type" << endl;
255                exit(0);
256        }
257
258
259        /** The color code used during visualization.
260        */
261        Environment::GetSingleton()->GetStringValue("ViewCells.Visualization.colorCode", buf);
262
263        if (strcmp(buf, "PVS") == 0)
264                mColorCode = 1;
265        else if (strcmp(buf, "MergedLeaves") == 0)
266                mColorCode = 2;
267        else if (strcmp(buf, "MergedTreeDiff") == 0)
268                mColorCode = 3;
269        else
270                mColorCode = 0;
271
272
273        Debug << "************ View Cells Manager options ***************" << endl;
274        Debug << "color code: " << mColorCode << endl;
275
276        Debug << "export rays: " << mExportRays << endl;
277        Debug << "export geometry: " << mExportGeometry << endl;
278        Debug << "max pvs ratio: " << mMaxPvsRatio << endl;
279       
280        Debug << "process only valid view cells: " << mOnlyValidViewCells << endl;
281        Debug << "construction samples: " << mConstructionSamples << endl;
282        Debug << "post process samples: " << mPostProcessSamples << endl;
283        Debug << "post process use rays for merge: " << mUseRaysForMerge << endl;
284        Debug << "visualization samples: " << mVisualizationSamples << endl;
285        Debug << "construction samples per pass: " << mSamplesPerPass << endl;
286        Debug << "export to file: " << mExportViewCells << endl;
287       
288        Debug << "active view cells: " << mNumActiveViewCells << endl;
289        Debug << "post process compress: " << mCompressViewCells << endl;
290        Debug << "visualization use clipPlane: " << mUseClipPlaneForViz << endl;
291        Debug << "post process merge: " << mMergeViewCells << endl;
292        Debug << "evaluate view cells: " << mEvaluateViewCells << endl;
293        Debug << "sampling type: " << mSamplingType << endl;
294        Debug << "evaluation sampling type: " << mEvaluationSamplingType << endl;
295        Debug << "show visualization: " << mShowVisualization << endl;
296        Debug << "filter width: " << mFilterWidth << endl;
297        Debug << "sample after subdivision: " << SAMPLE_AFTER_SUBDIVISION << endl;
298
299        Debug << "export bounding boxes: " << mExportBboxesForPvs << endl;
300        Debug << "export pvs for view cells: " << mExportPvs << endl;
301        Debug << "use kd pvs " << mUseKdPvs << endl;
302
303        Debug << "triangle weight: " << mTriangleWeight << endl;
304        Debug << "object weight: " << mObjectWeight << endl;
305
306        Debug << endl;
307}
308
309
310ViewCell *ViewCellsManager::GetViewCellById(const int id)
311{
312        ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
313
314        for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
315        {
316                if ((*vit)->GetId() == id)
317                        return (*vit);
318        }
319        return NULL;
320}
321
322
323bool ViewCellsManager::ExportRandomViewCells(const string &filename,
324                                                                                         const vector<ViewCellPoints *> &viewCells)
325{
326        std::ofstream outStream;
327        outStream.open(filename.c_str());
328
329        vector<ViewCellPoints *>::const_iterator vit, vit_end = viewCells.end();
330   
331        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
332        {
333                ViewCell *vc = (*vit)->first;
334
335                outStream << "v " << vc->GetId() << endl;
336
337                SimpleRayContainer viewPoints;
338       
339                SimpleRayContainer::const_iterator pit, pit_end = (*vit)->second.end();
340
341                for (pit = (*vit)->second.begin(); pit != pit_end; ++ pit)
342                {
343                        const Vector3 pt = (*pit).mOrigin;
344                        const Vector3 dir = (*pit).mDirection;
345
346                        outStream << "p " << pt.x  << " " << pt.y  << " " << pt.z
347                                      << " "  << dir.x << " " << dir.y << " " << dir.z << endl;
348                }
349        }
350
351        return true;
352}
353
354
355bool ViewCellsManager::GenerateRandomViewCells(vector<ViewCellPoints *> &viewCells,
356                                                                                           const int nViewCells,
357                                                                                           const int nViewPoints)
358{
359        ViewCellContainer rViewCells;
360
361        cout << "generating " << nViewCells << " random view cells" << endl;
362        ///GenerateRandomViewCells(rViewCells, nViewCells);
363
364        //cout << "finished" << endl;
365
366        //for (int i = 0; i < viewCells.size(); ++ i)
367        //      cout << "vc " << i << ": " << viewCells[i]->GetId() << endl;
368
369        cout << "generating " << nViewPoints << " view points per view cell" << endl;
370           
371        int generatedViewCells = 0;
372        int i = 0;
373    while (generatedViewCells < nViewCells)
374        {
375                ++ i;
376               
377                const int idx = (int)RandomValue(0.0f, (float)mViewCells.size() - 0.5f);
378                       
379                ViewCell *viewCell = GetViewCell(idx);
380               
381                cout << "testing view cell: " << viewCell->GetId() << endl;
382
383                if (!viewCell->Mailed())
384                {
385                        viewCell->Mail();
386
387                        SimpleRayContainer viewPoints;
388                       
389                        // generate random view points
390                        if (IsValidViewSpace(viewCell) &&
391                                GenerateViewPoints(viewCell, nViewPoints, viewPoints))
392                        {
393                                Debug << "vc: " << viewCell->GetId() << endl;
394
395                                ViewCellPoints *vcPts = new ViewCellPoints();
396                                viewCells.push_back(vcPts);
397
398                                // valid view cell found
399                                vcPts->first = viewCell;
400
401                                // generate view points
402                                ++ generatedViewCells;
403
404                                SimpleRayContainer::const_iterator pit, pit_end = viewPoints.end();
405
406                                for (pit = viewPoints.begin(); pit != pit_end; ++ pit)
407                                {
408                                        Debug << "vp: " << (*pit) << endl;
409                                        vcPts->second.push_back(*pit); 
410                                }
411                                cout << "view cell " << generatedViewCells << " generated: " << viewCell->GetId() << endl;     
412                        }
413                        else
414                        {
415                                cout << "error: invalid view cell " << generatedViewCells << " with id " << viewCell->GetId() << endl; 
416                        }
417                }
418
419                if (i > nViewCells * 1000000) // safety
420                {
421                        cout << "big error" << endl;
422                        break;
423                }
424                cout << "processd view cells " << generatedViewCells << " of " << nViewCells << endl << endl;
425        }
426
427        return true;
428}
429
430
431bool ViewCellsManager::ImportRandomViewCells(const string &filename,
432                                                                                         vector<ViewCellPoints *> &viewCells)
433{
434        ifstream inStream(filename.c_str());
435        if (!inStream.is_open())
436                return false;
437
438        ViewCellPoints *currentViewCell = NULL;
439
440        string buf;
441        while (!(getline(inStream, buf)).eof())
442        {
443                switch (buf[0])
444                {
445                case 'v':
446                        {
447                                int id;
448                                sscanf(buf.c_str(), "v %d", &id);
449                       
450                                currentViewCell = new ViewCellPoints();
451                                currentViewCell->first = GetViewCellById(id);
452                                               
453                                viewCells.push_back(currentViewCell);
454                                break;
455                        }
456                case 'p':
457                        {
458                                Vector3 pt, dir;
459                                sscanf(buf.c_str(), "p %f %f %f %f %f %f", &pt.x, &pt.y, &pt.z, &dir.x, &dir.y, &dir.z);
460                               
461                                SimpleRay ray(pt, dir, 0, 1);
462                                currentViewCell->second.push_back(ray);
463                                break;
464                        }
465                default:
466                        break;
467                }
468        }
469
470        return true;
471}
472
473
474bool ViewCellsManager::ImportRandomViewCells(const string &filename)
475{
476        return ImportRandomViewCells(filename, mViewCellPoints);
477}
478
479
480bool ViewCellsManager::GenerateViewPoints(ViewCell *viewCell,
481                                                                                  const int numViewPoints,
482                                                                                  SimpleRayContainer &viewPoints)
483{
484        bool success = true;
485        int generatedPts = 0;
486        int i = 0;
487
488        cout << "generating view points for view cell " << viewCell->GetId() << endl;
489
490        while (generatedPts < numViewPoints)
491        {
492                SimpleRay pt;
493
494                if (GenerateViewPoint(viewCell, pt))
495                {
496                        ++ generatedPts;
497                        cout << "generated view point " << generatedPts << endl;
498                        viewPoints.push_back(pt);
499                }
500
501                // savety criterium
502                if (++ i > numViewPoints * 3)
503                {
504                        return false;
505                }
506        }
507       
508        cout << "view point generation finished" << endl;
509
510        return true;
511}
512
513
514bool ViewCellsManager::ExportRandomViewCells(const string &filename)
515{
516        const int numViewCells = 100;
517        const int numViewPoints = 10;
518
519        preprocessor->mViewCellsManager->
520                GenerateRandomViewCells(mViewCellPoints, numViewCells, numViewPoints);
521
522        //cout << "exporting random view cells" << endl;
523        return preprocessor->mViewCellsManager->ExportRandomViewCells(filename,  mViewCellPoints);
524}
525
526
527bool ViewCellsManager::GenerateViewPoint(ViewCell *viewCell,
528                                                                                 SimpleRay &ray)
529{
530        // do not use this function since it could return different
531        // viewpoints for different executions of the algorithm
532
533        int tries = 0;
534        Vector3 viewPoint, direction;
535        const int maxTries = 10;
536
537        while (1)
538        {
539                // hack
540                if (!viewCell->GetMesh())
541                        CreateMesh(viewCell);
542
543        Mesh *mesh = viewCell->GetMesh();
544                AxisAlignedBox3 box = mesh->mBox;
545               
546                Vector3 pVector = Vector3(Random(1.0f),
547                                                                  Random(1.0f),
548                                                                  Random(1.0f));
549
550                viewPoint =  box.GetPoint(pVector);
551       
552                const Vector3 dVector = Vector3(2 * M_PI * Random(1.0f), M_PI * Random(1.0f), 0.0f);
553                direction = Normalize(Vector3(sin(dVector.x), 0.0f, cos(dVector.x)));
554
555                ViewCell *v = GetViewCell(viewPoint);
556
557                if (v && v->GetValid())
558                {
559                        mPreprocessor->GetRenderer()->mViewPoint = viewPoint;
560                        mPreprocessor->GetRenderer()->mViewDirection = direction;
561               
562                        if (mPreprocessor->GetRenderer()->ValidViewPoint())
563                        {
564                                cout << "view point valid " << viewPoint << " " << direction << endl;
565                                break;
566                        }
567                       
568                }
569
570                if (++ tries > maxTries)
571                {
572                        cerr << "error: no view point computed" << endl;
573                        return false;
574                }
575        }
576
577        ray = SimpleRay(viewPoint, direction, 0, 1);
578        //cout << "view point generated: " << viewPoint << " " << direction << endl;
579
580        return true;
581}
582
583
584bool ViewCellsManager::IsValidViewSpace(ViewCell *vc)
585{
586        SimpleRay simpleRay;
587        //check if view point can be generated
588        return GenerateViewPoint(vc, simpleRay);
589}
590
591
592bool ViewCellsManager::GenerateRandomViewCells(ViewCellContainer &viewCells,
593                                                                                           const int numViewCells)
594{
595        int generatedViewCells = 0;
596        //HaltonSequence halton;
597        //float r[1];
598
599        ViewCell::NewMail();
600
601        while (generatedViewCells < numViewCells)
602        {
603                // savety criterium
604                const int tries = 100000 + generatedViewCells;
605                int i = 0;
606
607                // generate next view cell
608                while (1)
609                {
610                        //halton.GetNext(1, r);
611                        //const int idx = (int)(r[0] * mViewCells.size() - 1.0f);
612                        const int idx = (int)RandomValue(0.0f, (float)mViewCells.size() - 0.5f);
613                       
614                        ViewCell *viewCell = GetViewCell(idx);
615
616                        if (!viewCell->Mailed())
617                        {
618                                viewCell->Mail();
619
620                                // check for valid view space
621                                if (IsValidViewSpace(viewCell))
622                                {
623                                        // valid view cell found
624                                        viewCells.push_back(viewCell);
625
626                        ++ generatedViewCells;
627                                        //cout << "view cell " << generatedViewCells << " generated: " << viewCell->GetId() << endl;   
628                                        break;
629                                }
630                                else
631                                {
632                                        cout << "error: invalid view cell " << generatedViewCells << " with id " << viewCell->GetId() << endl; 
633                                }
634                        }
635
636                        if (++ i == tries) // no new view cell fond
637                        {
638                                cerr << "big error! no view cell found" << endl;
639                                return false;
640                        }               
641                }                       
642        }
643
644        return true;
645}
646
647
648ViewCellsManager::~ViewCellsManager()
649{
650        // HACK: if view cells tree does not
651        // handle view cells, we have to do it here
652        // question: rather create view cells resource manager?
653        if (!ViewCellsTreeConstructed())
654        {
655                CLEAR_CONTAINER(mViewCells);
656        }
657        else
658        {
659                DEL_PTR(mViewCellsTree);
660        }
661
662        DEL_PTR(mMixtureDistribution);
663        CLEAR_CONTAINER(mViewCellPoints);
664}
665
666
667Intersectable *ViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
668{
669        if (mUseKdPvs)
670        {
671                KdNode *node = GetPreprocessor()->
672                        mKdTree->GetPvsNode(isTermination ?     ray.mTermination : ray.mOrigin);
673
674                return GetPreprocessor()->mKdTree->GetOrCreateKdIntersectable(node);
675        }
676        else
677        {
678                return isTermination ? ray.mTerminationObject : ray.mOriginObject;
679        }
680}
681
682
683void ViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
684{
685        GetPreprocessor()->mKdTree->CollectObjects(box, objects);
686}
687
688
689AxisAlignedBox3 ViewCellsManager::GetViewCellBox(ViewCell *vc)
690{
691        Mesh *m = vc->GetMesh();
692
693        if (m)
694        {
695                m->ComputeBoundingBox();
696                return m->mBox;
697        }
698
699        AxisAlignedBox3 box;
700        box.Initialize();
701
702        if (!vc->IsLeaf())
703        {
704                ViewCellInterior *vci = (ViewCellInterior *) vc;
705
706                ViewCellContainer::iterator it = vci->mChildren.begin();
707                for (; it != vci->mChildren.end(); ++it)
708                {
709                        box.Include(GetViewCellBox(*it));
710                }
711        }
712
713        return box;
714}
715
716
717int ViewCellsManager::CastPassSamples(const int samplesPerPass,
718                                                                          const vector<int> &strategies,
719                                                                          VssRayContainer &passSamples
720                                                                          ) const
721{
722        long startTime = GetTime();
723       
724        SimpleRayContainer simpleRays;
725       
726        simpleRays.reserve(samplesPerPass);
727        // reserve 2 times the size because always creates double rays
728        passSamples.reserve(samplesPerPass * 2);
729
730        // create one third of each type
731        int castRays = 0;
732       
733        const int numRaysPerPass = samplesPerPass / (int)strategies.size();
734        vector<int>::const_iterator iit, iit_end = strategies.end();
735
736        for (iit = strategies.begin(); iit != iit_end; ++ iit)
737        {
738                const int stype = *iit;
739                const int newRays =
740                        mPreprocessor->GenerateRays(numRaysPerPass, stype, simpleRays);
741
742                cout << "cast " << newRays << " rays of strategy " << stype << endl;
743                castRays += newRays;
744        }
745
746        cout << "generated " << samplesPerPass << " samples in "
747                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
748
749        startTime = GetTime();
750
751        // shoot simple ray and add it to importance samples
752        mPreprocessor->CastRays(simpleRays, passSamples, true);
753       
754        cout << "cast " <<  samplesPerPass << " samples in "
755                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
756
757        return (int)passSamples.size();
758}
759
760
761/// helper function which destroys rays or copies them into the output ray container
762inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
763{
764        cout << "disposing samples ... ";
765        long startTime = GetTime();
766        int n = (int)rays.size();
767
768        if (outRays)
769        {
770                VssRayContainer::const_iterator it, it_end = rays.end();
771                for (it = rays.begin(); it != it_end; ++ it)
772                {
773                        outRays->push_back(*it);
774                }
775        }
776        else
777        {
778                VssRayContainer::const_iterator it, it_end = rays.end();
779                for (it = rays.begin(); it != it_end; ++ it)
780                {
781                        if (!(*it)->IsActive())
782                                delete (*it);
783                }
784        }
785
786        cout << "finished" << endl;
787        Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
788}
789
790
791int ViewCellsManager::Construct(Preprocessor *preprocessor, VssRayContainer *outRays)
792{
793        int numSamples = 0;
794
795        SimpleRayContainer simpleRays;
796        VssRayContainer initialSamples;
797
798        // store pointer to preprocessor for further use during construction
799        mPreprocessor = preprocessor;
800       
801        // now decode distribution string
802        char mix[1024];
803        Environment::GetSingleton()->GetStringValue("RssPreprocessor.distributions", mix);
804        Debug << "using mixture distributions: " << mix << endl;
805
806        mMixtureDistribution = new MixtureDistribution(*mPreprocessor);
807        mMixtureDistribution->Construct(mix);
808
809        ///////////////////////////////////////////////////////
810        //-- Initial sampling for the construction of the view cell hierarchy.
811        //-- We use uniform sampling / box based sampling.
812       
813        long startTime = GetTime();
814        cout << "view cell construction: casting " << mInitialSamples << " initial samples ... " << endl;
815
816        // cast initial samples
817       
818        // mix of sampling strategies
819#if 0
820        vector<int>dummy;
821        dummy.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
822        dummy.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
823        dummy.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
824#endif
825        CastPassSamples(mInitialSamples, mStrategies, initialSamples);
826
827        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
828
829        // construct view cells
830        ConstructSubdivision(preprocessor->mObjects, initialSamples);
831
832        // initial samples count for overall samples ...
833        numSamples += mInitialSamples;
834
835        // rays can be passed or deleted
836        disposeRays(initialSamples, outRays);
837
838        cout << "time needed for initial construction: "
839                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
840
841        Debug << "time needed for initial construction: "
842                  << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
843
844        // collect view cells and compute statistics
845        ResetViewCells();
846
847
848        ///////////////////
849        //-- Initial hierarchy construction finished.
850        //-- We can do some stats and visualization
851       
852        if (0)
853        {
854                //-- export initial view cell partition
855                Debug << "\nView cells after initial sampling:\n" << mCurrentViewCellsStats << endl;
856
857                const string filename("viewcells.wrl");
858                Exporter *exporter = Exporter::GetExporter(filename.c_str());
859       
860                if (exporter)
861                {
862                        cout << "exporting initial view cells (=leaves) to " << filename.c_str() << " ... ";
863
864                        if (mExportGeometry)
865                        {
866                                exporter->ExportGeometry(preprocessor->mObjects);
867                        }
868
869                        exporter->SetWireframe();
870                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
871
872                        delete exporter;
873                        cout << "finished" << endl;
874                }
875        }
876
877
878        //////////////////////
879        //-- Cast some more sampling after initial construction.
880        //-- The additional rays can be used to gain
881        //-- some more information before the bottom-up merge
882        //-- note: guided rays could be used for this task
883
884        // time spent after construction of the initial partition
885        startTime = GetTime();
886        const int n = mConstructionSamples; //+initialSamples;
887
888        while (numSamples < n)
889        {
890                cout << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
891                Debug << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
892
893                VssRayContainer constructionSamples;
894
895                // cast new samples
896                numSamples += CastPassSamples(mSamplesPerPass,
897                                                                          mStrategies,
898                                                                          constructionSamples);
899
900                cout << "finished" << endl;
901                cout << "computing sample contribution for " << (int)constructionSamples.size() << " samples ... ";
902
903                // computes sample contribution of cast rays
904                if (SAMPLE_AFTER_SUBDIVISION)
905                        ComputeSampleContributions(constructionSamples, true, false);
906
907                cout << "finished" << endl;
908
909                disposeRays(constructionSamples, outRays);
910                cout << "total samples: " << numSamples << endl;
911        }
912
913        if (0)
914        {
915                ///////////////
916                //-- Get stats after the additional sampling step
917                //-- and before the bottom-up merge step
918
919                EvaluateViewCellsStats();
920                Debug << "\noriginal view cell partition before post process:\n"
921                          << mCurrentViewCellsStats << endl;
922       
923                mRenderer->RenderScene();
924                SimulationStatistics ss;
925                static_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
926
927                Debug << ss << endl;
928        }
929
930        ////////////////////
931        //-- post processing of the initial construction
932        //-- We can bottom-up merge the view cells in this step
933        //-- We can additionally cast some post processing sample rays.
934        //-- These rays can be used to store the view cells with the rays
935
936        VssRayContainer postProcessSamples;
937        cout << "casting " << mPostProcessSamples << " post process samples ..." << endl;
938       
939        CastPassSamples(mPostProcessSamples, mStrategies, postProcessSamples);
940
941        cout << "finished post process sampling" << endl;
942        cout << "starting post processing and visualization" << endl;
943
944        // store view cells with rays for post processing?
945        const bool storeViewCells = true;
946
947        if (SAMPLE_AFTER_SUBDIVISION)
948                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
949
950        PostProcess(preprocessor->mObjects, postProcessSamples);
951
952        const float secs = TimeDiff(startTime, GetTime()) * 1e-3f;
953        cout << "post processing (=merge) finished in " << secs << " secs" << endl;
954
955        Debug << "post processing time: " << secs << endl;
956        disposeRays(postProcessSamples, outRays);
957
958
959        ////////////////
960        //-- Evaluation of the resulting view cell partition.
961        //-- We cast a number of new samples and measure the render cost
962
963        if (mEvaluateViewCells)
964        {
965                EvalViewCellPartition();
966        }
967       
968        /////////////////
969        //-- Show some visualizations
970
971        if (mShowVisualization)
972        {
973                ///////////////
974                //-- visualization rays, e.g., to show some samples in the scene
975               
976                VssRayContainer visSamples;
977                int numSamples = CastPassSamples(mVisualizationSamples,
978                                                                                 mStrategies,
979                                                                                 visSamples);
980
981                if (SAMPLE_AFTER_SUBDIVISION)
982                        ComputeSampleContributions(visSamples, true, storeViewCells);
983
984                // various visualizations
985                Visualize(preprocessor->mObjects, visSamples);
986
987                disposeRays(visSamples, outRays);
988        }
989
990        // recalculate view cells
991        EvaluateViewCellsStats();
992
993        // compress the final solution
994        if (0) CompressViewCells();
995
996        // write view cells to disc
997        if (mExportViewCells)
998        {
999                char filename[100];
1000
1001                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
1002                ExportViewCells(filename, mExportPvs, mPreprocessor->mObjects);
1003        }
1004
1005        return numSamples;
1006}
1007
1008
1009AxisAlignedPlane *ViewCellsManager::GetClipPlane()
1010{
1011        return mUseClipPlaneForViz ? &mClipPlaneForViz : NULL;
1012}
1013
1014
1015ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
1016                                                                                                  ObjectContainer &pvsObjects,
1017                                                                                                  bool finalizeViewCells,
1018                                                                                                  BoundingBoxConverter *bconverter)
1019                                                                                                 
1020{
1021        if (!Debug.is_open()) Debug.open("debug.log");
1022
1023
1024        if (strstr(filename.c_str(), ".bn"))
1025        {
1026                Debug << "binary view cells format detected" << endl;
1027
1028                return LoadViewCellsBinary(filename,
1029                                               pvsObjects,
1030                                                                   finalizeViewCells,
1031                                                                   bconverter);
1032        }
1033        else
1034        {
1035                Debug << "xml view cells format detected" << endl;
1036
1037                // give just an empty container as parameter:
1038                // this loading function is used in the engine, thus it
1039                // does not need to load the entities the preprocessor works on
1040                ObjectContainer preprocessorObjects;
1041
1042                return LoadViewCells(filename,
1043                                         pvsObjects,
1044                                                         preprocessorObjects,
1045                                                         finalizeViewCells,
1046                                                         bconverter);
1047        }
1048}
1049
1050void ViewCellsManager::LoadIndexedBoundingBoxesBinary(IN_STREAM &stream, IndexedBoundingBoxContainer &iboxes)
1051{
1052        int numBoxes;
1053        stream.read(reinterpret_cast<char *>(&numBoxes), sizeof(int));
1054
1055        iboxes.reserve(numBoxes);
1056
1057        Vector3 bmin;
1058        Vector3 bmax;
1059        int id;
1060
1061        PerfTimer boxTimer;
1062
1063        boxTimer.Start();
1064        boxTimer.Entry();
1065       
1066        for (int i = 0; i < numBoxes; ++ i)
1067        {
1068                stream.read(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
1069                stream.read(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
1070                stream.read(reinterpret_cast<char *>(&id), sizeof(int));
1071
1072                iboxes.push_back(IndexedBoundingBox(id, AxisAlignedBox3(bmin, bmax)));
1073        }
1074
1075
1076        boxTimer.Exit();
1077
1078        Debug << numBoxes << " boxes loaded in " << boxTimer.TotalTime() << " secs" << endl;
1079}
1080
1081
1082ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
1083                                                                                                  ObjectContainer &pvsObjects,
1084                                                                                                  ObjectContainer &preprocessorObjects,
1085                                                                                                  bool finalizeViewCells,
1086                                                                                                  BoundingBoxConverter *bconverter)                                                                                             
1087{
1088        ViewCellsParser parser;
1089        ViewCellsManager *vm = NULL;
1090
1091        const long startTime = GetTime();
1092        const bool success = parser.ParseViewCellsFile(filename,
1093                                                                                                   &vm,
1094                                                                                                   pvsObjects,
1095                                                                                                   preprocessorObjects,
1096                                                                                                   bconverter);
1097
1098        if (!success)
1099        {
1100                Debug << "Error: loading view cells failed!" << endl;
1101                DEL_PTR(vm);
1102
1103                return NULL;
1104        }
1105       
1106        if (0) //hack: reset function should work, but something is wrong ..
1107        {
1108                vm->ResetViewCells();
1109        }
1110        else
1111        {
1112                ViewCellContainer leaves;
1113
1114                vm->mViewCells.clear();
1115                vm->mViewCellsTree->CollectLeaves(vm->mViewCellsTree->GetRoot(), leaves);
1116               
1117                ViewCellContainer::const_iterator it, it_end = leaves.end();
1118
1119                for (it = leaves.begin(); it != it_end; ++ it)
1120                {
1121                        vm->mViewCells.push_back(*it);
1122                }
1123        }
1124
1125        vm->mViewCellsFinished = true;
1126        vm->mMaxPvsSize = (int)pvsObjects.size();
1127
1128        if (finalizeViewCells)
1129        {
1130                // do some final computations, e.g.,
1131                // create the meshes and compute view cell volumes
1132                const bool createMeshes = true;
1133                vm->FinalizeViewCells(createMeshes);
1134        }
1135
1136        cout << (int)vm->mViewCells.size() << " view cells loaded in "
1137                 << TimeDiff(startTime, GetTime()) * 1e-3f << " secs" << endl;
1138
1139        Debug << (int)vm->mViewCells.size() << " view cells loaded in "
1140                  << TimeDiff(startTime, GetTime()) * 1e-3f << " secs" << endl;
1141       
1142        return vm;
1143}
1144
1145
1146bool VspBspViewCellsManager::ExportViewCells(const string filename,
1147                                                                                         const bool exportPvs,
1148                                                                                         const ObjectContainer &objects)
1149{
1150        // no view cells constructed yet
1151        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
1152                return false;
1153
1154        cout << "exporting view cells to xml ... ";
1155
1156        OUT_STREAM stream(filename.c_str());
1157
1158        // we need unique ids for each view cell
1159        CreateUniqueViewCellIds();
1160
1161        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
1162        stream << "<VisibilitySolution>" << endl;
1163
1164        if (exportPvs)
1165        {
1166                //-- export bounding boxes
1167                stream << "<BoundingBoxes>" << endl;
1168
1169                if (mUseKdPvs)
1170                {
1171                        vector<KdIntersectable *>::iterator kit, kit_end = GetPreprocessor()->mKdTree->mKdIntersectables.end();
1172
1173                        int id = 0;
1174                        for (kit = GetPreprocessor()->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
1175                        {
1176                                Intersectable *obj = *kit;
1177                                const AxisAlignedBox3 box = obj->GetBox();
1178                 
1179                                obj->SetId(id);
1180       
1181                                stream << "<BoundingBox" << " id=\"" << id << "\""
1182                                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1183                                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
1184                        }
1185                }
1186                else
1187                {
1188                        ObjectContainer::const_iterator oit, oit_end = objects.end();
1189               
1190                        for (oit = objects.begin(); oit != oit_end; ++ oit)
1191                        {
1192                                const AxisAlignedBox3 box = (*oit)->GetBox();
1193
1194                                ////////////
1195                                //-- the bounding boxes
1196
1197                                stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
1198                                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1199                                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
1200                        }
1201                }
1202
1203                stream << "</BoundingBoxes>" << endl;
1204        }
1205
1206       
1207        /////////////
1208        //-- export the view cells and the pvs
1209
1210        const int numViewCells = mCurrentViewCellsStats.viewCells;
1211        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
1212
1213        mViewCellsTree->Export(stream, exportPvs);
1214
1215        stream << "</ViewCells>" << endl;
1216
1217
1218        //////////
1219        //-- export the view space hierarchy
1220       
1221        stream << "<ViewSpaceHierarchy type=\"bsp\""
1222                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
1223                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
1224
1225        mVspBspTree->Export(stream);
1226        stream << "</ViewSpaceHierarchy>" << endl;
1227
1228        stream << "</VisibilitySolution>" << endl;
1229
1230        stream.close();
1231        cout << "finished" << endl;
1232
1233        return true;
1234}
1235
1236
1237void ViewCellsManager::EvalViewCellHistogram(const string filename,
1238                                                                                         const int nViewCells)
1239{
1240        std::ofstream outstream;
1241        outstream.open(filename.c_str());
1242
1243        ViewCellContainer viewCells;
1244       
1245        // the collect best viewcells does not work?
1246        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
1247
1248        float maxRenderCost, minRenderCost;
1249
1250        // sort by render cost
1251        sort(viewCells.begin(), viewCells.end(), SmallerRenderCost);
1252
1253        minRenderCost = viewCells.front()->GetRenderCost();
1254        maxRenderCost = viewCells.back()->GetRenderCost();
1255
1256        Debug << "histogram min rc: " << minRenderCost << " max rc: " << maxRenderCost << endl;
1257
1258    int histoIntervals;
1259        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
1260        const int intervals = min(histoIntervals, (int)viewCells.size());
1261
1262        int histoMaxVal;
1263        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
1264        maxRenderCost = min((float)histoMaxVal, maxRenderCost);
1265
1266       
1267        const float range = maxRenderCost - minRenderCost;
1268        const float stepSize = range / (float)intervals;
1269
1270        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
1271
1272        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
1273        const float totalVol = GetViewSpaceBox().GetVolume();
1274        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
1275
1276        int j = 0;
1277        int i = 0;
1278       
1279        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
1280
1281        // count for integral
1282        float volSum = 0;
1283        int smallerCostSum = 0;
1284       
1285        // note can skip computations for view cells already
1286        // evaluated and delete them from vector ...
1287    while (1)
1288        {
1289                // count for histogram value
1290                float volDif = 0;
1291                int smallerCostDif = 0;
1292
1293                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
1294                {
1295                        volSum += viewCells[i]->GetVolume();
1296                        volDif += viewCells[i]->GetVolume();
1297
1298                        ++ i;
1299                        ++ smallerCostSum;
1300                        ++ smallerCostDif;
1301                }
1302               
1303                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
1304                        break;
1305               
1306                const float rcRatio = currentRenderCost / maxRenderCost;
1307                const float volRatioSum = volSum / totalVol;
1308                const float volRatioDif = volDif / totalVol;
1309
1310                outstream << "#Pass\n" << j ++ << endl;
1311                outstream << "#RenderCostRatio\n" << rcRatio << endl;
1312                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
1313                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
1314                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
1315                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
1316                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
1317
1318                // increase current render cost
1319                currentRenderCost += stepSize;
1320        }
1321
1322        outstream.close();
1323}
1324
1325void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
1326                                                                                                           const int nViewCells)
1327{
1328        std::ofstream outstream;
1329        outstream.open(filename.c_str());
1330
1331        ViewCellContainer viewCells;
1332
1333#ifdef USE_BIT_PVS
1334        cout << "objects size: " << (int)ObjectPvsIterator::sObjects.size() << endl;
1335        cout << "pvs size: " <<  ObjectPvs::sPvsSize << endl;
1336#endif
1337
1338        // $$ JB hack - the collect best viewcells does not work?
1339#if 0
1340        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
1341#else
1342        viewCells = mViewCells;
1343#endif
1344
1345        ViewCellContainer::iterator it = viewCells.begin(), it_end = viewCells.end();           
1346       
1347        for (; it != it_end; ++it)
1348        {
1349                (*it)->UpdatePvsCost();
1350        }
1351
1352        float maxPvs, maxVal, minVal;
1353       
1354        // sort by pvs size
1355        sort(viewCells.begin(), viewCells.end(), SmallerPvs);
1356
1357        maxPvs = viewCells.back()->GetTrianglesInPvs();
1358        minVal = 0;
1359
1360        // hack: normalize pvs size
1361        int histoMaxVal;
1362        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
1363        maxVal = max((float)histoMaxVal, maxPvs);
1364               
1365        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
1366                << " real maxpvs " << maxPvs << endl;
1367
1368        int histoIntervals;
1369        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
1370        const int intervals = min(histoIntervals, (int)viewCells.size());
1371
1372        const float range = maxVal - minVal;
1373        int stepSize = (int)(range / intervals);
1374
1375        // set step size to avoid endless loop
1376        if (!stepSize) stepSize = 1;
1377       
1378        Debug << "intervals " << histoIntervals << endl;
1379        Debug << "stepsize: " << stepSize << endl;
1380        cout << "intervals " << histoIntervals << endl;
1381        cout << "stepsize: " << stepSize << endl;
1382
1383        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
1384        const float totalVol = GetViewSpaceBox().GetVolume();
1385
1386        float currentPvs = minVal;
1387       
1388        int i = 0;
1389        int j = 0;
1390        float volSum = 0;
1391        int smallerSum = 0;
1392
1393        it = viewCells.begin();
1394       
1395        for (int j = 0; j < intervals; ++ j)
1396        {
1397                float volDif = 0;
1398                int smallerDif = 0;
1399
1400                while ((i < (int)viewCells.size()) &&
1401                           (viewCells[i]->GetTrianglesInPvs() < currentPvs))
1402                {
1403                        volDif += viewCells[i]->GetVolume();
1404                        volSum += viewCells[i]->GetVolume();
1405
1406                        ++ i;
1407                        ++ smallerDif;
1408                        ++ smallerSum;
1409                }
1410               
1411                const float volRatioDif = volDif / totalVol;
1412                const float volRatioSum = volSum / totalVol;
1413
1414                outstream << "#Pass\n" << j << endl;
1415                outstream << "#Pvs\n" << currentPvs << endl;
1416                outstream << "#ViewCellsDif\n" << smallerDif << endl;
1417                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
1418                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
1419                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
1420       
1421                //-- increase current pvs size to define next interval
1422                currentPvs += stepSize;
1423        }
1424
1425        outstream.close();
1426}
1427
1428
1429void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
1430                                                                                                           ViewCellContainer &viewCells)
1431{
1432        std::ofstream outstream;
1433        outstream.open(filename.c_str());
1434
1435        float maxPvs, maxVal, minVal;
1436       
1437        // sort by pvs size
1438        sort(viewCells.begin(), viewCells.end(), SmallerPvs);
1439
1440        maxPvs = viewCells.back()->GetTrianglesInPvs();
1441        minVal = 0;
1442
1443        // hack: normalize pvs size
1444        int histoMaxVal;
1445        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
1446        maxVal = max((float)histoMaxVal, maxPvs);
1447               
1448        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
1449                << " real maxpvs " << maxPvs << endl;
1450
1451        int histoIntervals;
1452        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
1453        const int intervals = min(histoIntervals, (int)viewCells.size());
1454
1455        const float range = maxVal - minVal;
1456        int stepSize = (int)(range / intervals);
1457
1458        // set step size to avoid endless loop
1459        if (!stepSize) stepSize = 1;
1460       
1461        Debug << "intervals " << histoIntervals << endl;
1462        Debug << "stepsize: " << stepSize << endl;
1463        cout << "intervals " << histoIntervals << endl;
1464        cout << "stepsize: " << stepSize << endl;
1465
1466        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
1467        const float totalVol = GetViewSpaceBox().GetVolume();
1468
1469        float currentPvs = minVal;
1470       
1471        int i = 0;
1472        int j = 0;
1473        float volSum = 0;
1474        int smallerSum = 0;
1475
1476        //ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();   
1477       
1478        for (int j = 0; j < intervals; ++ j)
1479        {
1480                float volDif = 0;
1481                int smallerDif = 0;
1482
1483                while ((i < (int)viewCells.size()) &&
1484                           (viewCells[i]->GetTrianglesInPvs() < currentPvs))
1485                {
1486                        volDif += viewCells[i]->GetVolume();
1487                        volSum += viewCells[i]->GetVolume();
1488
1489                        ++ i;
1490                        ++ smallerDif;
1491                        ++ smallerSum;
1492                }
1493               
1494                //              if (0 && (i < (int)viewCells.size()))
1495                //                Debug << "new pvs cost increase: " << mViewCellsTree->GetTrianglesInPvs(viewCells[i])
1496                //                              << " " << currentPvs << endl;
1497               
1498                const float volRatioDif = volDif / totalVol;
1499                const float volRatioSum = volSum / totalVol;
1500
1501                outstream << "#Pass\n" << j << endl;
1502                outstream << "#Pvs\n" << currentPvs << endl;
1503                outstream << "#ViewCellsDif\n" << smallerDif << endl;
1504                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
1505                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
1506                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
1507       
1508                //-- increase current pvs size to define next interval
1509                currentPvs += stepSize;
1510        }
1511
1512        outstream.close();
1513}
1514
1515
1516bool ViewCellsManager::GetExportPvs() const
1517{
1518        return mExportPvs;
1519}
1520
1521
1522void ViewCellsManager::ResetPvs()
1523{
1524        if (ViewCellsTreeConstructed())
1525        {
1526                mViewCellsTree->ResetPvs();
1527        }
1528        else
1529        {
1530                cout << "view cells tree not constructed" << endl;
1531        }
1532}
1533
1534
1535void ViewCellsManager::ExportStats(const string &fileName)
1536{
1537        mViewCellsTree->ExportStats(fileName);
1538}
1539
1540
1541void ViewCellsManager::EvalViewCellPartition()
1542{
1543        int samplesPerPass;
1544        int numSamples;
1545        int castSamples = 0;
1546        char str[64];
1547        int oldSamples = 0;
1548
1549        int samplesForStats;
1550
1551        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
1552        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
1553        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
1554
1555        char statsPrefix[100];
1556        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
1557
1558        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
1559        Debug << "view cell evaluation samples: " << numSamples << endl;
1560        Debug << "view cell stats prefix: " << statsPrefix << endl;
1561
1562        cout << "reseting pvs ... ";
1563               
1564        const bool startFromZero = true;
1565
1566        // reset pvs and start over from zero
1567        if (startFromZero)
1568        {
1569                mViewCellsTree->ResetPvs();
1570        }
1571        else // start from current sampless
1572        {
1573                // statistics before casting more samples
1574                cout << "compute new statistics ... ";
1575                sprintf(str, "-%09d-eval.log", castSamples);
1576                string fName = string(statsPrefix) + string(str);
1577
1578                mViewCellsTree->ExportStats(fName);
1579                cout << "finished" << endl;
1580        }
1581
1582        cout << "finished" << endl;
1583    cout << "Evaluating view cell partition ... " << endl;
1584
1585        while (castSamples < numSamples)
1586        {               
1587                ///////////////
1588                //-- we have to use uniform sampling strategy for construction rays
1589
1590                VssRayContainer evaluationSamples;
1591                const int samplingType = mEvaluationSamplingType;
1592
1593                long startTime = GetTime();
1594
1595                cout << "casting " << samplesPerPass << " samples ... ";
1596                Debug << "casting " << samplesPerPass << " samples ... ";
1597
1598                CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
1599               
1600                castSamples += samplesPerPass;
1601
1602                Real timeDiff = TimeDiff(startTime, GetTime());
1603               
1604                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1605                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1606               
1607                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1608                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1609
1610                startTime = GetTime();
1611
1612                ComputeSampleContributions(evaluationSamples, true, false);
1613
1614                timeDiff = TimeDiff(startTime, GetTime());
1615                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1616                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1617
1618                if ((castSamples >= samplesForStats + oldSamples) || (castSamples >= numSamples))
1619                {
1620                        oldSamples += samplesForStats;
1621
1622                        ///////////
1623                        //-- output stats
1624
1625                        sprintf(str, "-%09d-eval.log", castSamples);
1626                        string fileName = string(statsPrefix) + string(str);
1627
1628                        ///////////////
1629                        //-- propagate pvs or pvs size information
1630
1631                        startTime = GetTime();
1632                        ObjectPvs pvs;
1633
1634                        cout << "updating pvs for evaluation ... " << endl;
1635
1636                        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
1637
1638                        timeDiff = TimeDiff(startTime, GetTime());
1639                        cout << "finished updating the pvs in " << timeDiff * 1e-3 << " secs" << endl;
1640                        Debug << "pvs evaluated in " << timeDiff * 1e-3 << " secs" << endl;
1641               
1642                        startTime = GetTime();
1643                        cout << "compute new statistics ... " << endl;
1644
1645                        ExportStats(fileName);
1646
1647                        timeDiff = TimeDiff(startTime, GetTime());
1648                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1649                        Debug << "statistis computed in " << timeDiff * 1e-3 << " secs" << endl;
1650                }
1651
1652                disposeRays(evaluationSamples, NULL);
1653        }
1654       
1655
1656        ////////////
1657        //-- histogram
1658
1659        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
1660        bool useHisto;
1661        int histoStepSize;
1662
1663        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
1664        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
1665
1666        if (useHisto)
1667        {
1668                // evaluate view cells in a histogram           
1669                char s[64];
1670
1671                for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
1672                {
1673                        string filename;
1674
1675                        cout << "computing histogram for " << pass << " view cells" << endl;
1676#if 0
1677                        //-- evaluate histogram for render cost
1678                        sprintf(s, "-%09d-histo.log", pass);
1679                        filename = string(statsPrefix) + string(s);
1680
1681                        EvalViewCellHistogram(filename, pass);
1682
1683#endif
1684                        //////////////////////////////////////////
1685            //-- evaluate histogram for pvs size
1686
1687                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
1688
1689                        sprintf(s, "-%09d-histo-pvs.log", pass);
1690                        filename = string(statsPrefix) + string(s);
1691
1692                        EvalViewCellHistogram(filename, pass);
1693                        //                      EvalViewCellHistogramForPvsSize(filename, pass);
1694                }
1695        }
1696}
1697
1698
1699inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
1700{
1701        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
1702}
1703
1704
1705/// Returns index of the best view cells of the neighborhood
1706static int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
1707{
1708        int bestViewCellIdx = 0;
1709
1710        float mergeCost = Limits::Infinity;
1711        int i = 0;
1712
1713        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
1714
1715        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
1716        {
1717                const float mc = EvalMergeCost(root, *vit);
1718               
1719                if (mc < mergeCost)
1720                {
1721                        mergeCost = mc;
1722                        bestViewCellIdx = i;
1723                }
1724        }
1725
1726        return bestViewCellIdx;
1727}
1728
1729
1730void ViewCellsManager::SetMaxFilterSize(const int size)
1731{
1732        mMaxFilterSize = size;
1733}
1734
1735
1736float ViewCellsManager::ComputeRenderCost(const int tri, const int obj) //const
1737{
1738        return max((float)tri * mTriangleWeight, (float)obj * mObjectWeight);
1739}
1740
1741
1742ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
1743                                                                                                        const ViewCellContainer &viewCells)
1744{
1745        ViewCell *root = currentViewCell;
1746        ViewCellContainer neighborhood = viewCells;
1747
1748        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
1749
1750        const int n = min(mMaxFilterSize, (int)neighborhood.size());
1751       
1752        /////////////////
1753        //-- use priority queue to merge leaf pairs
1754       
1755        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1756        {
1757                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
1758               
1759                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
1760       
1761                // remove from vector
1762                swap(neighborhood[bestViewCellIdx], neighborhood.back());
1763                neighborhood.pop_back();
1764       
1765                if (!bestViewCell || !root)
1766            cout << "warning!!" << endl;
1767               
1768                // create new root of the hierarchy
1769                root = MergeViewCells(root, bestViewCell);
1770        }
1771
1772        return root;   
1773}
1774
1775
1776struct SortableViewCellEntry {
1777
1778        SortableViewCellEntry() {}
1779        SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
1780
1781        float mValue;
1782        ViewCell *mViewCell;
1783
1784        friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
1785                return a.mValue < b.mValue;
1786        }
1787};
1788
1789
1790ViewCell * ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
1791                                                                                                          const ViewCellContainer &viewCells)
1792{
1793 
1794  vector<SortableViewCellEntry> neighborhood(viewCells.size());
1795  int i, j;
1796  for (i = 0, j = 0; i < viewCells.size(); i++) {
1797        if (viewCells[i] != currentViewCell)
1798          neighborhood[j++] = SortableViewCellEntry(
1799                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
1800                                                                                                viewCells[i]);
1801  }
1802  neighborhood.resize(j);
1803 
1804  sort(neighborhood.begin(), neighborhood.end());
1805 
1806  ViewCell *root = currentViewCell;
1807 
1808  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
1809 
1810  const int n = min(mMaxFilterSize, (int)neighborhood.size());
1811  //-- use priority queue to merge leaf pairs
1812 
1813  //cout << "neighborhood: " << neighborhood.size() << endl;
1814  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1815  {
1816          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
1817          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
1818          // create new root of the hierarchy
1819          root = MergeViewCells(root, bestViewCell);
1820          // set negative cost so that this view cell gets deleted
1821          root->SetMergeCost(-1.0f);
1822  }
1823 
1824  return root; 
1825}
1826
1827void
1828ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
1829                                                                           ) const
1830{
1831        if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f)
1832        {       
1833                ViewCellInterior *vci = (ViewCellInterior *) vc;
1834                ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
1835
1836        for (it = vci->mChildren.begin(); it != it_end; ++ it)
1837                        DeleteLocalMergeTree(*it);
1838               
1839                vci->mChildren.clear();
1840               
1841                delete vci;
1842  }
1843}
1844
1845
1846bool ViewCellsManager::CheckValidity(ViewCell *vc,
1847                                                                         int minPvsSize,
1848                                                                         int maxPvsSize) const
1849{
1850
1851        const float pvsCost = vc->GetPvs().EvalPvsCost();
1852
1853        if ((pvsCost > maxPvsSize) || (pvsCost < minPvsSize))
1854        {
1855                cout << "err: " << pvsCost << " " << minPvsSize << " " << maxPvsSize << endl;
1856                return false;
1857        }
1858
1859        return true;
1860}
1861
1862
1863int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1864                                                                                          ViewCellContainer &viewCells) const
1865{
1866        return 0;
1867};
1868
1869
1870AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1871                                                                                                const float width) const
1872{
1873  float w = Magnitude(mViewSpaceBox.Size())*width;
1874  Vector3 min = viewPoint - w * 0.5f;
1875  Vector3 max = viewPoint + w * 0.5f;
1876 
1877  return AxisAlignedBox3(min, max);
1878}
1879
1880
1881void ViewCellsManager::GetPrVS(const Vector3 &viewPoint,
1882                                                           PrVs &prvs,
1883                                                           const float filterWidth)
1884{
1885        ViewCell *currentViewCell = GetViewCell(viewPoint);
1886
1887        if (mMaxFilterSize < 1) {
1888                prvs.mViewCell = currentViewCell;
1889                return;
1890        }
1891
1892        const AxisAlignedBox3 box = GetFilterBBox(viewPoint, filterWidth);
1893
1894        if (currentViewCell)
1895        {
1896                ViewCellContainer viewCells;
1897                ComputeBoxIntersections(box, viewCells);
1898
1899                ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
1900                prvs.mViewCell = root;
1901
1902        }
1903        else
1904        {
1905                prvs.mViewCell = NULL;
1906                //prvs.mPvs = root->GetPvs();
1907        }
1908}
1909
1910
1911bool ViewCellsManager::ViewCellsTreeConstructed() const
1912{
1913    return (mViewCellsTree && mViewCellsTree->GetRoot());
1914}
1915
1916
1917void ViewCellsManager::SetValidity(ViewCell *vc,
1918                                                                   int minPvs,
1919                                                                   int maxPvs) const
1920{
1921        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1922}
1923
1924
1925void
1926ViewCellsManager::SetValidity(
1927                                                          int minPvsSize,
1928                                                          int maxPvsSize) const
1929{
1930        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1931
1932
1933        for (it = mViewCells.begin(); it != it_end; ++ it)
1934        {
1935                SetValidity(*it, minPvsSize, maxPvsSize);
1936        }
1937}
1938
1939void
1940ViewCellsManager::SetValidityPercentage(
1941                                                                                const float minValid,
1942                                                                                const float maxValid
1943                                                                                )
1944{
1945  ObjectPvs dummyPvs;
1946  // update pvs sizes
1947  for (int i = 0; i < (int)mViewCells.size(); ++ i) {
1948        UpdatePvsForEvaluation(mViewCells[i], dummyPvs);
1949  }
1950 
1951  sort(mViewCells.begin(), mViewCells.end(), SmallerPvs);
1952 
1953  int start = (int)(mViewCells.size() * minValid);
1954  int end = (int)(mViewCells.size() * maxValid);
1955 
1956  for (int i = 0; i < (int)mViewCells.size(); ++ i)
1957        {
1958          //      cout<<"pvs:"<<mViewCells[i]->GetCachedPvsCost()<<endl;
1959          mViewCells[i]->SetValid(i >= start && i <= end);
1960        }
1961}
1962
1963
1964int ViewCellsManager::CountValidViewcells() const
1965{
1966        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1967        int valid = 0;
1968
1969        for (it = mViewCells.begin(); it != it_end; ++ it)
1970        {       
1971                if ((*it)->GetValid())
1972                        ++ valid;
1973        }
1974
1975        return valid;
1976}
1977
1978
1979bool ViewCellsManager::LoadViewCellsGeometry(const string filename,
1980                                                                                         const bool extrudeBaseTriangles)
1981{
1982        /// we use predefined view cells from now on
1983        mUsePredefinedViewCells = true;
1984        X3dParser parser;
1985       
1986        if (extrudeBaseTriangles)
1987        {
1988                Environment::GetSingleton()->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
1989                const bool success = parser.ParseFile(filename, *this);
1990
1991                if (!success)
1992                        return false;
1993        }
1994        else
1995        {
1996                // hack: use standard mesh loading
1997                // create temporary scene graph for loading the view cells geometry
1998                // note: delete the meshes as they are created two times for transformed mesh instances.
1999                SceneGraphNode *root = new SceneGraphNode();
2000                const bool success = parser.ParseFile(filename, root, true);
2001               
2002                if (!success)
2003                {
2004                        DEL_PTR(root);
2005                        return false;
2006                }
2007
2008                ObjectContainer::const_iterator oit, oit_end = root->mGeometry.end();
2009               
2010                for (oit = root->mGeometry.begin(); oit != oit_end; ++ oit)
2011                {
2012                        Mesh *mesh;
2013                        if ((*oit)->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
2014                        {
2015                                TransformedMeshInstance *mit = static_cast<TransformedMeshInstance *>(*oit);
2016                                mesh = MeshManager::GetSingleton()->CreateResource();
2017                                mit->GetTransformedMesh(*mesh);
2018                        }
2019                        else if ((*oit)->Type() == Intersectable::MESH_INSTANCE)
2020                        {
2021                                MeshInstance *mit = static_cast<MeshInstance *>(*oit);
2022                                mesh = mit->GetMesh();
2023                        }
2024                        mesh->ComputeBoundingBox();
2025                        mViewCells.push_back(GenerateViewCell(mesh));
2026                }
2027
2028                DEL_PTR(root);
2029        }
2030
2031        // set view space box to bounding box of the view cells
2032        AxisAlignedBox3 bbox;
2033        bbox.Initialize();
2034        ViewCellContainer::iterator it = mViewCells.begin(), it_end = mViewCells.end();
2035
2036        for (; it != it_end; ++ it)
2037        {
2038                bbox.Include((*it)->GetMesh()->mBox);
2039        }
2040
2041        SetViewSpaceBox(bbox);
2042        cout << "view space box: " << bbox << endl;
2043        cout << "generated " << (int)mViewCells.size() << " view cells using the geometry " << filename << endl;
2044
2045        return true;
2046}
2047
2048
2049bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
2050{
2051  viewPoint = mViewSpaceBox.GetRandomPoint();
2052  return true;
2053}
2054
2055bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint, const Vector3 &params) const
2056{
2057  viewPoint = mViewSpaceBox.GetRandomPoint(params);
2058  return true;
2059}
2060
2061
2062float ViewCellsManager::GetViewSpaceVolume()
2063{
2064        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
2065}
2066
2067
2068bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
2069{
2070        if (!ViewCellsConstructed())
2071        {
2072                return mViewSpaceBox.IsInside(viewPoint);
2073        }
2074        else
2075        {
2076                if (!mViewSpaceBox.IsInside(viewPoint))
2077                        return false;
2078
2079                ViewCell *viewcell = GetViewCell(viewPoint);
2080
2081                if (!viewcell || !viewcell->GetValid())
2082                        return false;
2083        }
2084
2085        return true;
2086}
2087
2088
2089float
2090ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
2091                                                                                         const bool addContributions,
2092                                                                                         const bool storeViewCells,
2093                                                                                         const bool useHitObjects)
2094{
2095        float sum = 0.0f;
2096
2097        VssRayContainer::const_iterator it, it_end = rays.end();
2098
2099        for (it = rays.begin(); it != it_end; ++ it)
2100        {
2101                if (!ViewCellsConstructed())
2102                {
2103                        // view cells not yet constructed
2104                        // just take the lenghts of the rays as contributions
2105                        if ((*it)->mTerminationObject)
2106                        {
2107                                sum += (*it)->Length();
2108                        }
2109                }
2110                else
2111                {
2112                        sum += ComputeSampleContribution(*(*it), addContributions, storeViewCells, useHitObjects);
2113                }
2114        }
2115
2116        cout << "view cell cast time: " << viewCellCastTimer.TotalTime() << " s" << endl;
2117        Debug << "view cell cast time: " << viewCellCastTimer.TotalTime() << " s" << endl;
2118
2119        cout << "pvs time: " << pvsTimer.TotalTime() << " s" << endl;
2120        Debug << "pvs time: " << pvsTimer.TotalTime() << " s" << endl;
2121       
2122        return sum;
2123}
2124
2125
2126void ViewCellsManager::EvaluateViewCellsStats()
2127{
2128        mCurrentViewCellsStats.Reset();
2129        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2130
2131        for (it = mViewCells.begin(); it != it_end; ++ it)
2132        {
2133                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
2134        }
2135}
2136
2137
2138void ViewCellsManager::EvaluateRenderStatistics(float &totalRenderCost,
2139                                                                                                float &expectedRenderCost,
2140                                                                                                float &deviation,
2141                                                                                                float &variance,
2142                                                                                                float &totalCost,
2143                                                                                                float &avgRenderCost)
2144{
2145        ////////////
2146        //-- compute expected value
2147
2148        totalRenderCost = 0;
2149        totalCost = 0;
2150
2151        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2152
2153        for (it = mViewCells.begin(); it != it_end; ++ it)
2154        {
2155                ViewCell *vc = *it;
2156                totalRenderCost += vc->GetPvs().EvalPvsCost() * vc->GetVolume();
2157                totalCost += (int)vc->GetPvs().EvalPvsCost();
2158        }
2159
2160        // normalize with view space box
2161        totalRenderCost /= mViewSpaceBox.GetVolume();
2162        expectedRenderCost = totalRenderCost / (float)mViewCells.size();
2163        avgRenderCost = totalCost / (float)mViewCells.size();
2164
2165
2166        ///////////
2167        //-- compute standard defiation
2168
2169        variance = 0;
2170        deviation = 0;
2171
2172        for (it = mViewCells.begin(); it != it_end; ++ it)
2173        {
2174                ViewCell *vc = *it;
2175
2176                float renderCost = vc->GetPvs().EvalPvsCost() * vc->GetVolume();
2177                float dev;
2178
2179                if (1)
2180                        dev = fabs(avgRenderCost - (float)vc->GetPvs().EvalPvsCost());
2181                else
2182                        dev = fabs(expectedRenderCost - renderCost);
2183
2184                deviation += dev;
2185                variance += dev * dev;
2186        }
2187
2188        variance /= (float)mViewCells.size();
2189        deviation /= (float)mViewCells.size();
2190}
2191
2192
2193float ViewCellsManager::GetArea(ViewCell *viewCell) const
2194{
2195        return viewCell->GetArea();
2196}
2197
2198
2199float ViewCellsManager::GetVolume(ViewCell *viewCell) const
2200{
2201        return viewCell->GetVolume();
2202}
2203
2204
2205void ViewCellsManager::CompressViewCells()
2206{
2207        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
2208                return;
2209
2210        ////////////
2211        //-- compression
2212       
2213        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
2214
2215        cout << "number of entries before compress: " << pvsEntries << endl;
2216        Debug << "number of entries before compress: " << pvsEntries << endl;
2217
2218        mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
2219
2220        pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
2221
2222        Debug << "number of entries after compress: " << pvsEntries << endl;
2223        cout << "number of entries after compress: " << pvsEntries << endl;
2224}
2225
2226
2227ViewCell *ViewCellsManager::ExtrudeViewCell(const Triangle3 &baseTri,
2228                                                                                        const float height) const
2229{
2230        // one mesh per view cell
2231        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
2232//ootl::hash_map<int, Intersectable *> hmap(-2, NULL);
2233        ////////////
2234        //-- construct prism
2235
2236        // bottom
2237        mesh->mFaces.push_back(new Face(2,1,0));
2238        // top
2239    mesh->mFaces.push_back(new Face(3,4,5));
2240        // sides
2241        mesh->mFaces.push_back(new Face(1, 4, 3, 0));
2242        mesh->mFaces.push_back(new Face(2, 5, 4, 1));
2243        mesh->mFaces.push_back(new Face(3, 5, 2, 0));
2244
2245
2246        /////////////
2247        //-- extrude new vertices for top of prism
2248
2249        const Vector3 triNorm = baseTri.GetNormal();
2250        Triangle3 topTri;
2251
2252        // add base vertices and calculate top vertices
2253        for (int i = 0; i < 3; ++ i)
2254        {
2255                mesh->mVertices.push_back(baseTri.mVertices[i]);
2256        }
2257
2258        // add top vertices
2259        for (int i = 0; i < 3; ++ i)
2260        {
2261                mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
2262        }
2263
2264        // do we have to preprocess this mesh (we don't want to trace view cells!)?
2265        mesh->ComputeBoundingBox();
2266       
2267        return GenerateViewCell(mesh);
2268}
2269
2270
2271void ViewCellsManager::FinalizeViewCells(const bool createMesh)
2272{
2273        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2274
2275        // volume and area of the view cells are recomputed
2276        // a view cell mesh is created
2277        for (it = mViewCells.begin(); it != it_end; ++ it)
2278        {
2279                Finalize(*it, createMesh);
2280        }
2281
2282        mViewCellsTree->AssignRandomColors();
2283
2284        mTotalAreaValid = false;
2285}
2286
2287
2288void ViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
2289{
2290        // implemented in subclasses
2291}
2292
2293
2294/** fast way of merging 2 view cells.
2295*/
2296ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCell *left, ViewCell *right) const
2297{
2298        // generate parent view cell
2299        ViewCellInterior *vc = new ViewCellInterior();
2300
2301        vc->GetPvs().Clear();
2302        ObjectPvs::Merge(vc->GetPvs(), left->GetPvs(), right->GetPvs());
2303
2304        // set only links to child (not from child to parent, maybe not wished!!)
2305        vc->mChildren.push_back(left);
2306        vc->mChildren.push_back(right);
2307
2308        // update pvs size
2309        UpdateScalarPvsSize(vc, vc->GetPvs().EvalPvsCost(), vc->GetPvs().GetSize());
2310
2311        return vc;
2312}
2313
2314
2315ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCellContainer &children) const
2316{
2317        ViewCellInterior *vc = new ViewCellInterior();
2318        ViewCellContainer::const_iterator it, it_end = children.end();
2319
2320        for (it = children.begin(); it != it_end; ++ it)
2321        {
2322                vc->GetPvs().MergeInPlace((*it)->GetPvs());
2323       
2324                vc->mChildren.push_back(*it);
2325        }
2326
2327        return vc;
2328}
2329
2330
2331void ViewCellsManager::SetRenderer(Renderer *renderer)
2332{
2333        mRenderer = renderer;
2334}
2335
2336
2337ViewCellsTree *ViewCellsManager::GetViewCellsTree()
2338{
2339        return mViewCellsTree;
2340}
2341
2342
2343void ViewCellsManager::SetVisualizationSamples(const int visSamples)
2344{
2345        mVisualizationSamples = visSamples;
2346}
2347
2348
2349void ViewCellsManager::SetConstructionSamples(const int constructionSamples)
2350{
2351        mConstructionSamples = constructionSamples;
2352}
2353
2354
2355void ViewCellsManager::SetInitialSamples(const int initialSamples)
2356{
2357        mInitialSamples = initialSamples;
2358}
2359
2360
2361void ViewCellsManager::SetPostProcessSamples(const int postProcessSamples)
2362{
2363        mPostProcessSamples = postProcessSamples;
2364}
2365
2366
2367int ViewCellsManager::GetVisualizationSamples() const
2368{
2369        return mVisualizationSamples;
2370}
2371
2372
2373int ViewCellsManager::GetConstructionSamples() const
2374{
2375        return mConstructionSamples;
2376}
2377
2378
2379int ViewCellsManager::GetPostProcessSamples() const
2380{
2381        return mPostProcessSamples;
2382}
2383
2384
2385void ViewCellsManager::UpdatePvs()
2386{
2387        if (mViewCellPvsIsUpdated || !ViewCellsTreeConstructed())
2388                return;
2389
2390        mViewCellPvsIsUpdated = true;
2391
2392        ViewCellContainer leaves;
2393        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
2394
2395        ViewCellContainer::const_iterator it, it_end = leaves.end();
2396
2397        for (it = leaves.begin(); it != it_end; ++ it)
2398        {
2399                mViewCellsTree->PropagatePvs(*it);
2400        }
2401}
2402
2403
2404void ViewCellsManager::GetPvsStatistics(PvsStatistics &stat)
2405{
2406  // update pvs of view cells tree if necessary
2407  if (0) UpdatePvs();
2408 
2409  ViewCellContainer::const_iterator it = mViewCells.begin();
2410 
2411  stat.viewcells = 0;
2412  stat.minPvs = 100000000;
2413  stat.maxPvs = 0;
2414  stat.avgPvs = 0.0f;
2415  stat.avgPvsEntries = 0.0f;
2416  stat.avgFilteredPvs = 0.0f;
2417  stat.avgFilteredPvsEntries = 0.0f;
2418  stat.avgFilterContribution = 0.0f;
2419  stat.avgFilterRadius = 0;
2420  stat.avgFilterRatio = 0;
2421  stat.avgRelPvsIncrease = 0.0f;
2422  stat.devRelPvsIncrease = 0.0f;
2423  stat.renderCost = 0.0f;
2424  stat.mem = 0.0f;
2425
2426  if (mPerViewCellStat.size() != mViewCells.size()) {
2427        // reset the pvs size array after the first call to this routine
2428        mPerViewCellStat.resize(mViewCells.size());
2429        for (int i=0; i < mPerViewCellStat.size(); i++) {
2430          mPerViewCellStat[i].pvsSize = 0.0f;
2431          mPerViewCellStat[i].relPvsIncrease = 0.0f;
2432        }
2433  }
2434  int i;
2435  bool evaluateFilter;
2436  Environment::GetSingleton()->GetBoolValue("Preprocessor.evaluateFilter", evaluateFilter);
2437
2438  const float vol = mViewSpaceBox.GetVolume();
2439
2440  for (i = 0; it != mViewCells.end(); ++ it, ++ i)
2441  {
2442          ViewCell *viewcell = *it;
2443          if (viewcell->GetValid()) {
2444                  const float pvsCost = mViewCellsTree->GetTrianglesInPvs(viewcell);
2445                  const float renderCost = pvsCost * viewcell->GetVolume() / vol;
2446
2447                  if (pvsCost < stat.minPvs)
2448                          stat.minPvs = pvsCost;
2449                  if (pvsCost > stat.maxPvs)
2450                          stat.maxPvs = pvsCost;
2451
2452                  stat.avgPvs += pvsCost;
2453                  stat.renderCost += renderCost;
2454
2455                  const float pvsEntries = (float)mViewCellsTree->GetPvsEntries(viewcell);
2456                  stat.avgPvsEntries += pvsEntries;
2457
2458                  if (mPerViewCellStat[i].pvsSize > 0.0f)
2459                          mPerViewCellStat[i].relPvsIncrease = (pvsCost - mPerViewCellStat[i].pvsSize) / mPerViewCellStat[i].pvsSize;
2460
2461                  stat.avgRelPvsIncrease += mPerViewCellStat[i].relPvsIncrease;
2462
2463                  // update the pvs size
2464                  mPerViewCellStat[i].pvsSize = pvsCost;
2465
2466
2467                  if (evaluateFilter)
2468                  {
2469                          ObjectPvs filteredPvs;
2470
2471                          PvsFilterStatistics fstat = ApplyFilter2(viewcell, false, mFilterWidth, filteredPvs);
2472
2473                          const float filteredCost = filteredPvs.EvalPvsCost();
2474
2475                          stat.avgFilteredPvs += filteredCost;
2476                          stat.avgFilteredPvsEntries += filteredPvs.GetSize();
2477
2478                          stat.avgFilterContribution += filteredCost - pvsCost;
2479
2480                          stat.avgFilterRadius += fstat.mAvgFilterRadius;
2481                          int sum = fstat.mGlobalFilterCount + fstat.mLocalFilterCount;
2482                          if (sum) {
2483                                  stat.avgFilterRatio += fstat.mLocalFilterCount /
2484                                          (float) sum;
2485                          }
2486
2487                  } else {
2488                          stat.avgFilteredPvs += pvsCost;
2489                          stat.avgFilterContribution += 0;
2490                  }
2491
2492                  ++ stat.viewcells;
2493          }
2494  }
2495
2496
2497
2498  if (stat.viewcells) {
2499          stat.mem = (float)(ObjectPvs::GetEntrySizeByte() * stat.avgPvsEntries + stat.viewcells * 16) / float(1024 * 1024);
2500
2501          stat.avgPvs/=stat.viewcells;
2502          stat.avgPvsEntries/=stat.viewcells;
2503          stat.avgFilteredPvsEntries/=stat.viewcells;
2504          stat.avgFilteredPvs/=stat.viewcells;
2505          stat.avgFilterContribution/=stat.viewcells;
2506          stat.avgFilterRadius/=stat.viewcells;
2507          stat.avgFilterRatio/=stat.viewcells;
2508          stat.avgRelPvsIncrease/=stat.viewcells;
2509          stat.renderCostRatio=stat.renderCost / stat.mem;
2510
2511          // evaluate std deviation of relPvsIncrease
2512          float sum=0.0f;
2513          for (i=0; i < stat.viewcells; i++) {
2514                  sum += sqr(mPerViewCellStat[i].relPvsIncrease - stat.avgRelPvsIncrease);
2515          }
2516          stat.devRelPvsIncrease = sqrt(sum/stat.viewcells);
2517  }
2518
2519}
2520
2521
2522void ViewCellsManager::PrintPvsStatistics(ostream &s)
2523{
2524  s<<"############# Viewcell PVS STAT ##################\n";
2525  PvsStatistics pvsStat;
2526  GetPvsStatistics(pvsStat);
2527  s<<"#AVG_PVS\n"<<pvsStat.avgPvs<<endl;
2528  s<<"#AVG_ENTRIES_PVS\n"<<pvsStat.avgPvsEntries<<endl;
2529  s<<"#RENDERCOST\n"<<pvsStat.renderCost<<endl;
2530  s<<"#AVG_FILTERED_PVS\n"<<pvsStat.avgFilteredPvs<<endl;
2531  s<<"#AVG_FILTERED_ENTRIES_PVS\n"<<pvsStat.avgFilteredPvsEntries<<endl;
2532  s<<"#AVG_FILTER_CONTRIBUTION\n"<<pvsStat.avgFilterContribution<<endl;
2533  s<<"#AVG_FILTER_RADIUS\n"<<pvsStat.avgFilterRadius<<endl;
2534  s<<"#AVG_FILTER_RATIO\n"<<pvsStat.avgFilterRatio<<endl;
2535  s<<"#MAX_PVS\n"<<pvsStat.maxPvs<<endl;
2536  s<<"#MIN_PVS\n"<<pvsStat.minPvs<<endl;
2537  s<<"#AVG_REL_PVS_INCREASE\n"<<pvsStat.avgRelPvsIncrease<<endl;
2538  s<<"#DEV_REL_PVS_INCREASE\n"<<pvsStat.devRelPvsIncrease<<endl;
2539  s<<"#MEMORY\n"<<pvsStat.mem<<endl;
2540  s<<"#RATIO\n"<<pvsStat.renderCost / (pvsStat.mem + Limits::Small)<<endl;
2541  s<<"#CONTRIBUTING_RAYS\n"<<mSamplesStat.mContributingRays<<endl;
2542
2543  if (mSamplesStat.mRays) {
2544        s<<"#AVG_VIEWCELLS_PER_RAY\n"<<mSamplesStat.mViewCells/(float)mSamplesStat.mRays<<endl;
2545  } else {
2546        s<<"#AVG_VIEWCELLS_PER_RAY\n 1 \n";
2547  }
2548  mSamplesStat.Reset();
2549}
2550
2551
2552int ViewCellsManager::CastBeam(Beam &beam)
2553{
2554        return 0;
2555}
2556
2557
2558ViewCellContainer &ViewCellsManager::GetViewCells()
2559{
2560        return mViewCells;
2561}
2562
2563
2564void ViewCellsManager::SetViewSpaceBox(const AxisAlignedBox3 &box)
2565{
2566        mViewSpaceBox = box;
2567       
2568        // hack: create clip plane relative to new view space box
2569        CreateClipPlane();
2570        // the total area of the view space has changed
2571        mTotalAreaValid = false;
2572}
2573
2574
2575void ViewCellsManager::CreateClipPlane()
2576{
2577        int axis = 0;
2578        float pos;
2579        bool orientation;
2580        Vector3 absPos;
2581
2582        Environment::GetSingleton()->GetFloatValue("ViewCells.Visualization.clipPlanePos", pos);
2583        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.clipPlaneAxis", axis);
2584
2585        if (axis < 0)
2586        {
2587                axis = -axis;
2588                orientation = false;
2589                absPos = mViewSpaceBox.Max() -  mViewSpaceBox.Size() * pos;
2590        }
2591        else
2592        {
2593                orientation = true;
2594                absPos = mViewSpaceBox.Min() +  mViewSpaceBox.Size() * pos;
2595        }
2596
2597        mClipPlaneForViz = AxisAlignedPlane(axis, absPos[axis]);
2598        mClipPlaneForViz.mOrientation = orientation;
2599}
2600
2601
2602AxisAlignedBox3 ViewCellsManager::GetViewSpaceBox() const
2603{
2604        return mViewSpaceBox;
2605}
2606
2607
2608void ViewCellsManager::ResetViewCells()
2609{
2610        // recollect view cells
2611        mViewCells.clear();
2612        CollectViewCells();
2613       
2614        // stats are computed once more
2615        EvaluateViewCellsStats();
2616
2617        // has to be recomputed
2618        mTotalAreaValid = false;
2619}
2620
2621
2622int ViewCellsManager::GetMaxPvsSize() const
2623{
2624        return mMaxPvsSize;
2625}
2626
2627
2628int ViewCellsManager::GetMinPvsSize() const
2629{
2630        return mMinPvsSize;
2631}
2632
2633
2634
2635float ViewCellsManager::GetMaxPvsRatio() const
2636{
2637        return mMaxPvsRatio;
2638}
2639
2640
2641inline static void AddSampleToPvs(ObjectPvs &pvs,
2642                                                                  Intersectable *obj,
2643                                                                  const float pdf)
2644{
2645#if PVS_ADD_DIRTY
2646        pvs.AddSampleDirtyCheck(obj, pdf);
2647
2648        if (pvs.RequiresResort())
2649        {
2650                pvs.SimpleSort();
2651        }
2652#else
2653        pvs.AddSample(obj, pdf);
2654#endif
2655}
2656
2657
2658void ViewCellsManager::SortViewCellPvs()
2659{
2660        ViewCellContainer::iterator it, it_end = mViewCells.end();
2661       
2662        for (it = mViewCells.begin(); it != it_end; ++ it)
2663        {
2664                ObjectPvs &pvs = (*it)->GetPvs();
2665                if (pvs.RequiresResortLog())
2666                        pvs.SimpleSort();
2667        }
2668}
2669
2670
2671void ViewCellsManager::ComputeViewCellContribution(ViewCell *viewCell,
2672                                                                                                   VssRay &ray,
2673                                                                                                   Intersectable *obj,
2674                                                                                                   const Vector3 &pt,
2675                                                                                                   const bool addSamplesToPvs)
2676{
2677        // check if we are outside of view space
2678        // $$JB tmp commented to speedup up computations
2679#if 0
2680        if (!obj || !viewCell->GetValid())
2681                return;
2682#endif
2683
2684        // if ray not outside of view space
2685        float relContribution = 0.0f;
2686        float absContribution = 0.0f;
2687        bool hasAbsContribution;
2688
2689        // todo: maybe not correct for kd node pvs
2690        if (addSamplesToPvs)
2691        {
2692                hasAbsContribution = viewCell->GetPvs().AddSampleDirtyCheck(obj, ray.mPdf);
2693                //hasAbsContribution = viewCell->GetPvs().AddSample(obj,ray.mPdf);
2694        }
2695        else
2696        {
2697                hasAbsContribution =
2698                        viewCell->GetPvs().GetSampleContribution(obj, ray.mPdf, relContribution);
2699        }
2700
2701        // $$ clear the relative contribution as it is currently not correct anyway
2702        //  relContribution = 0.0f;
2703
2704        if (hasAbsContribution) 
2705        {
2706                ++ ray.mPvsContribution;
2707                absContribution = relContribution = 1.0f;
2708
2709                if (viewCell->GetPvs().RequiresResort())
2710                        viewCell->GetPvs().SimpleSort();
2711
2712#if CONTRIBUTION_RELATIVE_TO_PVS_SIZE
2713                relContribution /= viewcell->GetPvs().GetSize();
2714#endif
2715
2716#if DIST_WEIGHTED_CONTRIBUTION
2717                // recalculate the contribution - weight the 1.0f contribution by the sqr distance to the
2718                // object-> a new contribution in the proximity of the viewcell has a larger weight!
2719                relContribution /=
2720                        SqrDistance(GetViewCellBox(viewcell).Center(), ray.mTermination);
2721
2722#endif
2723        }
2724
2725#if SUM_RAY_CONTRIBUTIONS || AVG_RAY_CONTRIBUTIONS
2726        ray.mRelativePvsContribution += relContribution;
2727#else
2728        // recalculate relative contribution - use max of Rel Contribution
2729        if (ray.mRelativePvsContribution < relContribution)
2730                ray.mRelativePvsContribution = relContribution;
2731#endif
2732}
2733
2734
2735int ViewCellsManager::GetNumViewCells() const
2736{
2737        return (int)mViewCells.size();
2738}
2739
2740
2741void
2742ViewCellsManager::DeterminePvsObjects(
2743                                                                          VssRayContainer &rays,
2744                                                                          const bool useHitObjects)
2745{
2746        if (!useHitObjects)
2747        {
2748                // store higher order object (e.g., bvh node) instead of object itself
2749                VssRayContainer::const_iterator it, it_end = rays.end();
2750       
2751                for (it = rays.begin(); it != it_end; ++ it)
2752                {
2753                        VssRay *vssRay = *it;
2754
2755                        // set only the termination object
2756                        vssRay->mTerminationObject = GetIntersectable(*vssRay, true);
2757                }
2758        }
2759}
2760
2761
2762float ViewCellsManager::ComputeSampleContribution(VssRay &ray,
2763                                                                                                  const bool addRays,
2764                                                                                                  ViewCell *currentViewCell,
2765                                                                                                  const bool useHitObjects)
2766{
2767        ray.mPvsContribution = 0;
2768        ray.mRelativePvsContribution = 0.0f;
2769
2770        if (!ray.mTerminationObject)
2771                return 0.0f;
2772
2773        // optain pvs entry (can be different from hit object)
2774        Intersectable *terminationObj;
2775
2776        terminationObj = ray.mTerminationObject;
2777
2778        ComputeViewCellContribution(currentViewCell,
2779                                                                ray,
2780                                                                terminationObj,
2781                                                                ray.mTermination,
2782                                                                addRays);
2783       
2784#if USE_RAY_LENGTH_AS_CONTRIBUTION
2785        float c = 0.0f;
2786        if (terminationObj)
2787                c = ray.Length();
2788
2789        ray.mRelativePvsContribution = ray.mPvsContribution = c;
2790        return c;
2791#else
2792        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
2793          (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
2794#endif
2795}
2796
2797
2798float
2799ViewCellsManager::ComputeSampleContribution(VssRay &ray,
2800                                                                                        const bool addRays,
2801                                                                                        const bool storeViewCells,
2802                                                                                        const bool useHitObjects)
2803{
2804        ray.mPvsContribution = 0;
2805        ray.mRelativePvsContribution = 0.0f;
2806
2807        ++ mSamplesStat.mRays;
2808
2809        if (!ray.mTerminationObject)
2810                return 0.0f;
2811
2812        static Ray hray;
2813        hray.Init(ray);
2814
2815        float tmin = 0, tmax = 1.0;
2816
2817        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
2818        {
2819                // cerr<<"ray outside view space box\n";
2820                return 0;
2821        }
2822
2823        Vector3 origin = hray.Extrap(tmin);
2824        Vector3 termination = hray.Extrap(tmax);
2825
2826        ViewCell::NewMail();
2827
2828        viewCellCastTimer.Entry();
2829
2830        static ViewCellContainer viewCells;
2831        static VssRay *lastVssRay = NULL;
2832
2833        // check if last ray was not same ray with reverse direction
2834        if (1)
2835                // tmp matt: don't use when origin objects are not accounted for, currently the second ray is lost!!
2836                //!lastVssRay ||
2837                //!(ray.mOrigin == lastVssRay->mTermination) ||
2838                //!(ray.mTermination == lastVssRay->mOrigin))
2839        {
2840                viewCells.clear();
2841
2842                // traverse the view space subdivision
2843                CastLineSegment(origin, termination, viewCells);
2844
2845                lastVssRay = &ray;
2846        }
2847
2848        viewCellCastTimer.Exit();
2849
2850        mSamplesStat.mViewCells += (int)viewCells.size();
2851
2852        if (storeViewCells)
2853        {       
2854                // cerr << "Store viewcells should not be used in the test!" << endl;
2855                // copy viewcells memory efficiently
2856#if VSS_STORE_VIEWCELLS
2857                ray.mViewCells.reserve(viewCells.size());
2858                ray.mViewCells = viewCells;
2859#else
2860                cerr << "Vss store viewcells not supported." << endl;
2861                exit(1);
2862#endif
2863        }
2864
2865        Intersectable *terminationObj;
2866
2867        objTimer.Entry();
2868
2869        // obtain pvs entry (can be different from hit object)
2870        terminationObj = ray.mTerminationObject;
2871
2872        objTimer.Exit();
2873
2874        pvsTimer.Entry();
2875
2876        ViewCellContainer::const_iterator it = viewCells.begin();
2877
2878        for (; it != viewCells.end(); ++ it)
2879        {
2880                ComputeViewCellContribution(*it,
2881                                                ray,
2882                                                                        terminationObj,
2883                                                                        ray.mTermination,
2884                                                                        addRays);
2885                (*it)->IncNumPiercingRays();
2886        }
2887
2888        pvsTimer.Exit();
2889
2890        mSamplesStat.mPvsContributions += ray.mPvsContribution;
2891        if (ray.mPvsContribution)
2892                ++ mSamplesStat.mContributingRays;
2893
2894#if AVG_RAY_CONTRIBUTIONS
2895        ray.mRelativePvsContribution /= (float)viewCells.size();
2896#endif
2897
2898#if USE_RAY_LENGTH_AS_CONTRIBUTION
2899        float c = 0.0f;
2900        if (terminationObj)
2901                c = ray.Length();
2902        ray.mRelativePvsContribution = ray.mPvsContribution = c;
2903        return c;
2904#else
2905        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
2906                (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
2907#endif
2908}
2909
2910
2911void ViewCellsManager::GetRaySets(const VssRayContainer &sourceRays,
2912                                                                  const int maxSize,
2913                                                                  VssRayContainer &usedRays,
2914                                                                  VssRayContainer *savedRays) const
2915{
2916        const int limit = min(maxSize, (int)sourceRays.size());
2917        const float prop = (float)limit / ((float)sourceRays.size() + Limits::Small);
2918
2919        VssRayContainer::const_iterator it, it_end = sourceRays.end();
2920        for (it = sourceRays.begin(); it != it_end; ++ it)
2921        {
2922                if (Random(1.0f) < prop)
2923                        usedRays.push_back(*it);
2924                else if (savedRays)
2925                        savedRays->push_back(*it);
2926        }
2927}
2928
2929
2930float ViewCellsManager::GetRendercost(ViewCell *viewCell) const
2931{
2932        return (float)mViewCellsTree->GetTrianglesInPvs(viewCell);
2933}
2934
2935
2936float ViewCellsManager::GetAccVcArea()
2937{
2938        // if already computed
2939        if (mTotalAreaValid)
2940        {
2941                return mTotalArea;
2942        }
2943
2944        mTotalArea = 0;
2945        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2946
2947        for (it = mViewCells.begin(); it != it_end; ++ it)
2948        {
2949                //Debug << "area: " << GetArea(*it);
2950        mTotalArea += GetArea(*it);
2951        }
2952
2953        mTotalAreaValid = true;
2954
2955        return mTotalArea;
2956}
2957
2958
2959void ViewCellsManager::PrintStatistics(ostream &s) const
2960{
2961        s << mCurrentViewCellsStats << endl;
2962}
2963
2964
2965void ViewCellsManager::CreateUniqueViewCellIds()
2966{
2967        if (ViewCellsTreeConstructed())
2968        {
2969                mViewCellsTree->CreateUniqueViewCellsIds();
2970        }
2971        else // no view cells tree, handle view cells "myself"
2972        {
2973                int i = 0;
2974                ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
2975                for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
2976                {
2977                        if ((*vit)->GetId() != OUT_OF_BOUNDS_ID)
2978                        {
2979                                mViewCells[i]->SetId(i ++);
2980                        }
2981                }
2982        }
2983}
2984
2985
2986void ViewCellsManager::ExportViewCellsForViz(Exporter *exporter,
2987                                                                                         const AxisAlignedBox3 *sceneBox,
2988                                                                                         const bool colorCode,
2989                                                                                         const AxisAlignedPlane *clipPlane
2990                                                                                         ) const
2991{
2992        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2993
2994        for (it = mViewCells.begin(); it != it_end; ++ it)
2995        {
2996                if (!mOnlyValidViewCells || (*it)->GetValid())
2997                {
2998                        ExportColor(exporter, *it, colorCode); 
2999                        ExportViewCellGeometry(exporter, *it, sceneBox, clipPlane);
3000                }
3001        }
3002}
3003
3004
3005void ViewCellsManager::CreateViewCellMeshes()
3006{
3007        // convert to meshes
3008        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
3009
3010        for (it = mViewCells.begin(); it != it_end; ++ it)
3011        {
3012                if (!(*it)->GetMesh())
3013                {
3014                        CreateMesh(*it);
3015                }
3016        }
3017}
3018
3019
3020bool ViewCellsManager::ExportViewCells(const string filename,
3021                                                                           const bool exportPvs,
3022                                                                           const ObjectContainer &objects)
3023{
3024        return false;
3025}
3026
3027
3028void ViewCellsManager::CollectViewCells(const int n)
3029{
3030        mNumActiveViewCells = n;
3031        mViewCells.clear();
3032        // implemented in subclasses
3033        CollectViewCells();
3034}
3035
3036
3037void ViewCellsManager::SetViewCellActive(ViewCell *vc) const
3038{
3039        ViewCellContainer leaves;
3040        // sets the pointers to the currently active view cells
3041        mViewCellsTree->CollectLeaves(vc, leaves);
3042
3043        ViewCellContainer::const_iterator lit, lit_end = leaves.end();
3044        for (lit = leaves.begin(); lit != lit_end; ++ lit)
3045        {
3046                static_cast<ViewCellLeaf *>(*lit)->SetActiveViewCell(vc);
3047        }
3048}
3049
3050
3051void ViewCellsManager::SetViewCellsActive()
3052{
3053        // collect leaf view cells and set the pointers to
3054        // the currently active view cells
3055        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
3056
3057        for (it = mViewCells.begin(); it != it_end; ++ it)
3058        {
3059                SetViewCellActive(*it);
3060        }
3061}
3062
3063
3064int ViewCellsManager::GetMaxFilterSize() const
3065{
3066        return mMaxFilterSize; 
3067}
3068
3069
3070static const bool USE_ASCII = true;
3071
3072
3073bool ViewCellsManager::ExportBoundingBoxes(const string filename,
3074                                                                                   const ObjectContainer &objects) const
3075{
3076        ObjectContainer::const_iterator it, it_end = objects.end();
3077       
3078        if (USE_ASCII)
3079        {
3080                ofstream boxesOut(filename.c_str());
3081                if (!boxesOut.is_open())
3082                        return false;
3083
3084                for (it = objects.begin(); it != it_end; ++ it)
3085                {
3086                        MeshInstance *mi = static_cast<MeshInstance *>(*it);
3087                        const AxisAlignedBox3 box = mi->GetBox();
3088
3089                        boxesOut << mi->GetId() << " "
3090                                         << box.Min().x << " "
3091                                         << box.Min().y << " "
3092                                         << box.Min().z << " "
3093                                         << box.Max().x << " "
3094                                         << box.Max().y << " "
3095                     << box.Max().z << endl;   
3096                }
3097
3098                boxesOut.close();
3099        }
3100        else
3101        {
3102                ofstream boxesOut(filename.c_str(), ios::binary);
3103
3104                if (!boxesOut.is_open())
3105                        return false;
3106
3107                for (it = objects.begin(); it != it_end; ++ it)
3108                {       
3109                        MeshInstance *mi = static_cast<MeshInstance *>(*it);
3110                        const AxisAlignedBox3 box = mi->GetBox();
3111                       
3112                        Vector3 bmin = box.Min();
3113                        Vector3 bmax = box.Max();
3114                       
3115                        int id = mi->GetId();
3116
3117                        boxesOut.write(reinterpret_cast<char *>(&id), sizeof(int));
3118                        boxesOut.write(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
3119                        boxesOut.write(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
3120                }
3121               
3122                boxesOut.close();
3123        }
3124
3125        return true;
3126}
3127
3128
3129bool ViewCellsManager::LoadBoundingBoxes(const string filename,
3130                                                                                 IndexedBoundingBoxContainer &boxes) const
3131{
3132        Vector3 bmin, bmax;
3133        int id;
3134
3135        if (USE_ASCII)
3136        {
3137                ifstream boxesIn(filename.c_str());
3138               
3139                if (!boxesIn.is_open())
3140                {
3141                        cout << "failed to open file " << filename << endl;
3142                        return false;
3143                }
3144
3145                string buf;
3146                while (!(getline(boxesIn, buf)).eof())
3147                {
3148                        sscanf(buf.c_str(), "%d %f %f %f %f %f %f",
3149                                   &id, &bmin.x, &bmin.y, &bmin.z,
3150                                   &bmax.x, &bmax.y, &bmax.z);
3151               
3152                        AxisAlignedBox3 box(bmin, bmax);
3153                        //      MeshInstance *mi = new MeshInstance();
3154                        // HACK: set bounding box to new box
3155                        //mi->mBox = box;
3156
3157                        boxes.push_back(IndexedBoundingBox(id, box));
3158                }
3159
3160                boxesIn.close();
3161        }
3162        else
3163        {
3164                ifstream boxesIn(filename.c_str(), ios::binary);
3165
3166                if (!boxesIn.is_open())
3167                        return false;
3168
3169                while (1)
3170                {
3171                        boxesIn.read(reinterpret_cast<char *>(&id), sizeof(Vector3));
3172                        boxesIn.read(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
3173                        boxesIn.read(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
3174                       
3175                        if (boxesIn.eof())
3176                                break;
3177                       
3178                        AxisAlignedBox3 box(bmin, bmax);
3179                        MeshInstance *mi = new MeshInstance(NULL);
3180
3181                        boxes.push_back(IndexedBoundingBox(id, box));
3182                }
3183
3184                boxesIn.close();
3185        }
3186
3187        return true;
3188}
3189
3190
3191float ViewCellsManager::GetFilterWidth()
3192{
3193        return mFilterWidth;
3194}
3195
3196
3197float ViewCellsManager::GetAbsFilterWidth()
3198{
3199        return Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
3200}
3201
3202
3203void ViewCellsManager::UpdateScalarPvsSize(ViewCell *vc,
3204                                                                                   const float pvsCost,
3205                                                                                   const int entriesInPvs) const
3206{
3207        vc->mPvsCost = pvsCost;
3208        vc->mEntriesInPvs = entriesInPvs;
3209
3210        vc->mPvsSizeValid = true;
3211}
3212
3213
3214void
3215ViewCellsManager::ApplyFilter(ViewCell *viewCell,
3216                                                          KdTree *kdTree,
3217                                                          const float viewSpaceFilterSize,
3218                                                          const float spatialFilterSize,
3219                                                          ObjectPvs &pvs
3220                                                          )
3221{
3222  // extend the pvs of the viewcell by pvs of its neighbors
3223  // and apply spatial filter by including all neighbors of the objects
3224  // in the pvs
3225
3226  // get all viewcells intersecting the viewSpaceFilterBox
3227  // and compute the pvs union
3228 
3229  //Vector3 center = viewCell->GetBox().Center();
3230  //  Vector3 center = m->mBox.Center();
3231
3232        //  AxisAlignedBox3 box(center - Vector3(viewSpaceFilterSize/2),
3233        //                                        center + Vector3(viewSpaceFilterSize/2));
3234        if (!ViewCellsConstructed())
3235                return;
3236
3237        if (viewSpaceFilterSize >= 0.0f)
3238        {
3239                const bool usePrVS = false;
3240
3241                if (!usePrVS)
3242                {
3243                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
3244                        box.Enlarge(Vector3(viewSpaceFilterSize/2));
3245
3246                        ViewCellContainer viewCells;
3247                        ComputeBoxIntersections(box, viewCells);
3248
3249                        //  cout<<"box="<<box<<endl;
3250                        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();
3251
3252                        for (; it != it_end; ++ it)
3253                        {
3254                                ObjectPvs interPvs;
3255                                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
3256                                ObjectPvs::Merge(interPvs, pvs, (*it)->GetPvs());
3257
3258                                pvs = interPvs;
3259                        }
3260                }
3261                else
3262                {
3263                        PrVs prvs;
3264                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
3265
3266                        //  mViewCellsManager->SetMaxFilterSize(1);
3267                        GetPrVS(box.Center(), prvs, viewSpaceFilterSize);
3268                        pvs = prvs.mViewCell->GetPvs();
3269                        DeleteLocalMergeTree(prvs.mViewCell);
3270                }
3271        }
3272        else
3273        {
3274                pvs = viewCell->GetPvs();
3275        }
3276
3277        if (spatialFilterSize >=0.0f)
3278                ApplySpatialFilter(kdTree, spatialFilterSize, pvs);
3279
3280}
3281
3282
3283
3284void
3285ViewCellsManager::ApplyFilter(KdTree *kdTree,
3286                                                          const float relViewSpaceFilterSize,
3287                                                          const float relSpatialFilterSize
3288                                                          )
3289{
3290
3291        if (!ViewCellsConstructed())
3292                return;
3293
3294        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
3295
3296        ObjectPvs *newPvs;
3297        newPvs = new ObjectPvs[mViewCells.size()];
3298
3299        float viewSpaceFilterSize = Magnitude(mViewSpaceBox.Size())*relViewSpaceFilterSize;
3300        float spatialFilterSize = Magnitude(kdTree->GetBox().Size())*relSpatialFilterSize;
3301       
3302        int i;
3303        for (i=0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
3304          ApplyFilter(*it,
3305                                  kdTree,
3306                                  viewSpaceFilterSize,
3307                                  spatialFilterSize,
3308                                  newPvs[i]
3309                                  );
3310        }
3311       
3312        // now replace all pvss
3313        for (i = 0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
3314         
3315          ObjectPvs &pvs = (*it)->GetPvs();
3316          pvs.Clear();
3317          pvs = newPvs[i];
3318          newPvs[i].Clear();
3319        }
3320
3321        delete [] newPvs;
3322}
3323
3324
3325void
3326ViewCellsManager::ApplySpatialFilter(
3327                                                                         KdTree *kdTree,
3328                                                                         const float spatialFilterSize,
3329                                                                         ObjectPvs &pvs
3330                                                                         )
3331{
3332        // now compute a new Pvs by including also objects intersecting the
3333        // extended boxes of visible objects
3334        Intersectable::NewMail();
3335
3336        ObjectPvsIterator pit = pvs.GetIterator();
3337
3338        while (pit.HasMoreEntries())
3339                pit.Next()->Mail();
3340
3341        ObjectPvs nPvs;
3342        int nPvsSize = 0;
3343
3344        ObjectPvsIterator pit2 = pvs.GetIterator();
3345
3346        while (pit2.HasMoreEntries())
3347        {               
3348                // now go through the pvs again
3349                Intersectable *object = pit2.Next();
3350
3351                //      Vector3 center = object->GetBox().Center();
3352                //      AxisAlignedBox3 box(center - Vector3(spatialFilterSize/2),
3353                //                                              center + Vector3(spatialFilterSize/2));
3354
3355                AxisAlignedBox3 box = object->GetBox();
3356                box.Enlarge(Vector3(spatialFilterSize/2));
3357
3358                ObjectContainer objects;
3359
3360                // $$ warning collect objects takes only unmailed ones!
3361                kdTree->CollectObjects(box, objects);
3362                //      cout<<"collected objects="<<objects.size()<<endl;
3363                ObjectContainer::const_iterator noi = objects.begin();
3364                for (; noi != objects.end(); ++ noi)
3365                {
3366                        Intersectable *o = *noi;
3367                        cout<<"w";
3368                        // $$ JB warning: pdfs are not correct at this point!     
3369                        nPvs.AddSample(o, Limits::Small);
3370                        nPvsSize ++;
3371                }
3372        }
3373
3374        // cout<<"nPvs size = "<<nPvsSize<<endl;
3375        pvs.MergeInPlace(nPvs);
3376}
3377
3378
3379void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
3380                                                                                                const ViewCellContainer &viewCells) const
3381{
3382        MergeViewCellsRecursivly(pvs, viewCells, 0, (int)viewCells.size() - 1);
3383}
3384
3385
3386void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
3387                                                                                                const ViewCellContainer &viewCells,
3388                                                                                                const int leftIdx,
3389                                                                                                const int rightIdx) const
3390{
3391        if (leftIdx == rightIdx)
3392        {
3393                pvs = viewCells[leftIdx]->GetPvs();
3394        }
3395        else
3396        {
3397                const int midSplit = (leftIdx + rightIdx) / 2;
3398       
3399                ObjectPvs leftPvs, rightPvs;
3400                MergeViewCellsRecursivly(leftPvs, viewCells, leftIdx, midSplit);
3401                MergeViewCellsRecursivly(rightPvs, viewCells, midSplit, rightIdx);
3402
3403        ObjectPvs::Merge(pvs, leftPvs, rightPvs);
3404        }
3405}
3406
3407
3408PvsFilterStatistics
3409ViewCellsManager::ApplyFilter2(ViewCell *viewCell,
3410                                                           const bool useViewSpaceFilter,
3411                                                           const float filterSize,
3412                                                           ObjectPvs &pvs,
3413                                                           vector<AxisAlignedBox3> *filteredBoxes
3414                                                           )
3415{
3416        pvs.Reserve(viewCell->GetFilteredPvsSize());
3417
3418        PvsFilterStatistics stats;
3419
3420        AxisAlignedBox3 vbox = GetViewCellBox(viewCell);
3421        const Vector3 center = vbox.Center();
3422       
3423        // copy the PVS
3424        if (!mUseKdPvs)
3425                Intersectable::NewMail();
3426        else
3427                KdNode::NewMail();
3428
3429        ObjectPvs basePvs = viewCell->GetPvs();
3430        ObjectPvsIterator pit = basePvs.GetIterator();
3431
3432        if (!mUseKdPvs)
3433        {       // first mark all objects from this pvs
3434                while (pit.HasMoreEntries())   
3435                        pit.Next()->Mail();
3436        }
3437
3438        int pvsSize = 0;
3439        int nPvsSize = 0;
3440       
3441        //Debug<<"f #s="<<samples<<"  pvs size = "<<basePvs.GetSize();
3442        //  cout<<"Filter size = "<<filterSize<<endl;
3443        //  cout<<"vbox = "<<vbox<<endl;
3444        //  cout<<"center = "<<center<<endl;
3445
3446
3447        // Minimal number of local samples to take into account
3448        // the local sampling density.
3449        // The size of the filter is a minimum of the conservative
3450        // local sampling density estimate (#rays intersecting teh viewcell and
3451        // the object)
3452        // and gobal estimate for the view cell
3453        // (total #rays intersecting the viewcell)
3454        const int minLocalSamples = 2;
3455        const float viewCellRadius = 0.5f * Magnitude(vbox.Diagonal());
3456
3457        float samples = (float)basePvs.GetSamples();
3458
3459
3460        //////////
3461        //-- now compute the filter box around the current viewCell
3462
3463        if (useViewSpaceFilter)
3464        {
3465                // float radius = Max(viewCellRadius/100.0f, avgRadius - viewCellRadius);
3466                float radius = viewCellRadius / 100.0f;
3467                vbox.Enlarge(radius);
3468                cout<<"vbox = "<<vbox<<endl;
3469
3470                ViewCellContainer viewCells;
3471                ComputeBoxIntersections(vbox, viewCells);
3472
3473                ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();
3474
3475                for (int i = 0; it != it_end; ++ it, ++ i)
3476                {
3477                        if ((*it) != viewCell)
3478                        {
3479                                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
3480                                basePvs.MergeInPlace((*it)->GetPvs());
3481                        }
3482
3483                        // update samples and globalC
3484                        samples = (float)pvs.GetSamples();
3485                        //      cout<<"neighboring viewcells = "<<i-1<<endl;
3486                        //      cout<<"Samples' = "<<samples<<endl;
3487                }
3488        }
3489
3490        // Minimal number of samples so that filtering takes place
3491        const float MIN_SAMPLES = 50;
3492
3493        if (samples > MIN_SAMPLES)
3494        {
3495                float globalC = 2.0f * filterSize / sqrt(samples);
3496
3497                ObjectContainer objects;
3498                PvsData pvsData;
3499
3500                pit = basePvs.GetIterator();
3501
3502                while (pit.HasMoreEntries())
3503                {               
3504                        Intersectable *object = pit.Next(pvsData);
3505
3506                        // compute filter size based on the distance and the numebr of samples
3507                        AxisAlignedBox3 box = object->GetBox();
3508
3509                        float distance = Distance(center, box.Center());
3510                        float globalRadius = distance*globalC;
3511
3512                        int objectSamples = (int)pvsData.mSumPdf;
3513                        float localRadius = MAX_FLOAT;
3514
3515                        localRadius = filterSize*0.5f*Magnitude(box.Diagonal())/
3516                                sqrt((float)objectSamples);
3517
3518                        // cout<<"os="<<objectSamples<<" lr="<<localRadius<<" gr="<<globalRadius<<endl;
3519
3520                        // now compute the filter size
3521                        float radius;
3522
3523#if 0
3524                        if (objectSamples <= 1)
3525                        {
3526                                if (localRadius > globalRadius)
3527                                {
3528                                        radius = 0.5flRadius;
3529                                        stats.mLocalFilterCount++;
3530                                }
3531                                else
3532                                {
3533                                        radius = globalRadius;
3534                                        stats.mGlobalFilterCount++;
3535                                }
3536                        }
3537                        else
3538                        {
3539                                radius = localRadius;
3540                                stats.mLocalFilterCount++;
3541                        }
3542#else
3543
3544                        // radius = 0.5f*globalRadius + 0.5f*localRadius;
3545                        radius = Min(globalRadius, localRadius);
3546
3547                        if (localRadius > globalRadius)
3548                                ++ stats.mLocalFilterCount;
3549                        else
3550                                ++ stats.mGlobalFilterCount;
3551#endif
3552
3553                        stats.mAvgFilterRadius += radius;
3554
3555                        // cout<<"box = "<<box<<endl;
3556                        //      cout<<"distance = "<<distance<<endl;
3557                        //      cout<<"radiues = "<<radius<<endl;
3558
3559                        box.Enlarge(Vector3(radius));
3560
3561                        if (filteredBoxes)
3562                                filteredBoxes->push_back(box);
3563
3564                        objects.clear();
3565
3566                        // $$ warning collect objects takes only unmailed ones!
3567                        if (mUseKdPvs)
3568                                GetPreprocessor()->mKdTree->CollectKdObjects(box, objects);
3569                        else
3570                                CollectObjects(box, objects);
3571
3572                        //      cout<<"collected objects="<<objects.size()<<endl;
3573                        ObjectContainer::const_iterator noi = objects.begin();
3574                        for (; noi != objects.end(); ++ noi)
3575                        {
3576                                Intersectable *o = *noi;
3577                                // $$ JB warning: pdfs are not correct at this point!     
3578                                pvs.AddSampleDirty(o, Limits::Small);
3579                        }
3580                }
3581               
3582                stats.mAvgFilterRadius /= (stats.mLocalFilterCount + stats.mGlobalFilterCount);
3583        }
3584
3585        //Debug << " nPvs size = " << pvs.GetSize() << endl;
3586
3587        if (!mUseKdPvs)
3588        {
3589                PvsData pvsData;
3590
3591                // copy the base pvs to the new pvs
3592                pit = basePvs.GetIterator();
3593                while (pit.HasMoreEntries())
3594                {               
3595                        Intersectable *obj = pit.Next(pvsData);
3596                        pvs.AddSampleDirty(obj, pvsData.mSumPdf);
3597                }
3598        }
3599
3600        pvs.SimpleSort();
3601        viewCell->SetFilteredPvsSize(pvs.GetSize());
3602
3603        // warning: not thread-safe!
3604        if (!mUseKdPvs)
3605                Intersectable::NewMail();
3606
3607        return stats;
3608}
3609
3610
3611
3612void ViewCellsManager::ExportColor(Exporter *exporter,
3613                                                                   ViewCell *vc,
3614                                                                   int colorCode) const
3615{
3616        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
3617
3618        float importance = 0;
3619        static Material m;
3620        //cout << "color code: " << colorCode << endl;
3621               
3622        switch (colorCode)
3623        {
3624        case 0: // Random
3625                {
3626                        if (vcValid)
3627                        {
3628                                m.mDiffuseColor.r = 0.2f + RandomValue(0.0f, 0.8f);
3629                                m.mDiffuseColor.g = 0.2f + RandomValue(0.0f, 0.8f);
3630                                m.mDiffuseColor.b = 0.2f + RandomValue(0.0f, 0.8f);
3631                        }
3632                        else
3633                        {
3634                                m.mDiffuseColor.r = 0.0f;
3635                                m.mDiffuseColor.g = 1.0f;
3636                                m.mDiffuseColor.b = 0.0f;
3637                        }
3638
3639                        exporter->SetForcedMaterial(m);
3640                        return;
3641                }
3642               
3643        case 1: // pvs
3644                {
3645                        if (mCurrentViewCellsStats.maxPvs)
3646                        {
3647                                importance = //(float)mViewCellsTree->GetTrianglesInPvs(vc) / 700;
3648                                                         (float)mCurrentViewCellsStats.maxPvs;
3649                        }
3650                }
3651                break;
3652        case 2: // merges
3653                {
3654            const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
3655                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
3656                }
3657                break;
3658        default:
3659                break;
3660        }
3661
3662        // special color code for invalid view cells
3663        m.mDiffuseColor.r = importance;
3664        m.mDiffuseColor.b = 1.0f;//vcValid ? 0.0f : 1.0f;
3665        m.mDiffuseColor.g = 1.0f - importance;
3666
3667        //Debug << "importance: " << importance << endl;
3668        exporter->SetForcedMaterial(m);
3669}
3670
3671
3672void ViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3673                                                                                          vector<MergeCandidate> &candidates)
3674{
3675        // implemented in subclasses
3676}
3677
3678
3679void ViewCellsManager::UpdatePvsForEvaluation()
3680{
3681        ObjectPvs objPvs;
3682        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), objPvs);
3683}
3684
3685
3686void ViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
3687{
3688        // terminate traversal
3689        if (root->IsLeaf())
3690        {
3691                // we assume that pvs is explicitly stored in leaves
3692                pvs = root->GetPvs();
3693                UpdateScalarPvsSize(root, pvs.EvalPvsCost(), pvs.GetSize());
3694
3695                return;
3696        }
3697
3698        ////////////////
3699        //-- interior node => propagate pvs up the tree
3700
3701        ViewCellInterior *interior = static_cast<ViewCellInterior *>(root);
3702
3703        // reset interior pvs
3704        interior->GetPvs().Clear();
3705
3706        // reset recursive pvs
3707        pvs.Clear();
3708
3709        // pvss of child nodes
3710        vector<ObjectPvs> pvsList;
3711        pvsList.resize((int)interior->mChildren.size());
3712
3713        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
3714       
3715        int i = 0;
3716
3717        ////////
3718        //-- recursivly compute child pvss
3719
3720        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ i)
3721        {
3722                UpdatePvsForEvaluation(*vit, pvsList[i]);
3723        }
3724
3725#if 1
3726        Intersectable::NewMail();
3727
3728
3729        ///////////
3730        //-- merge pvss
3731
3732        PvsData pvsData;
3733
3734        vector<ObjectPvs>::iterator oit = pvsList.begin();
3735
3736        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
3737        {
3738                ObjectPvsIterator pit = (*oit).GetIterator();
3739               
3740                // add pvss to new pvs: use mailing to avoid adding entries two times.
3741                while (pit.HasMoreEntries())
3742                {               
3743                        Intersectable *intersect = pit.Next(pvsData);
3744
3745                        if (!intersect->Mailed())
3746                        {
3747                                intersect->Mail();
3748                                pvs.AddSampleDirty(intersect, pvsData.mSumPdf);
3749                        }
3750                }
3751        }
3752
3753        // store pvs in this node
3754        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
3755        {
3756                interior->SetPvs(pvs);
3757        }
3758       
3759        // set new pvs size
3760        UpdateScalarPvsSize(interior, pvs.EvalPvsCost(), pvs.GetSize());
3761       
3762#else
3763        // really merge cells: slow but sumPdf is correct
3764        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
3765        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
3766#endif
3767}
3768
3769
3770
3771/*******************************************************************/
3772/*               BspViewCellsManager implementation                */
3773/*******************************************************************/
3774
3775
3776BspViewCellsManager::BspViewCellsManager(ViewCellsTree *vcTree, BspTree *bspTree):
3777ViewCellsManager(vcTree), mBspTree(bspTree)
3778{
3779        Environment::GetSingleton()->GetIntValue("BspTree.Construction.samples", mInitialSamples);
3780
3781        mBspTree->SetViewCellsManager(this);
3782        mBspTree->SetViewCellsTree(mViewCellsTree);
3783}
3784
3785
3786bool BspViewCellsManager::ViewCellsConstructed() const
3787{
3788        return mBspTree->GetRoot() != NULL;
3789}
3790
3791
3792ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
3793{
3794        return new BspViewCell(mesh);
3795}
3796
3797
3798int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3799                                                                                          const VssRayContainer &rays)
3800{
3801        // if view cells were already constructed, we can finish
3802        if (ViewCellsConstructed())
3803                return 0;
3804
3805        int sampleContributions = 0;
3806
3807        // construct view cells using the collected samples
3808        RayContainer constructionRays;
3809        VssRayContainer savedRays;
3810
3811        // choose a a number of rays based on the ratio of cast rays / requested rays
3812        const int limit = min(mInitialSamples, (int)rays.size());
3813        VssRayContainer::const_iterator it, it_end = rays.end();
3814
3815        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
3816
3817        for (it = rays.begin(); it != it_end; ++ it)
3818        {
3819                if (Random(1.0f) < prop)
3820                        constructionRays.push_back(new Ray(*(*it)));
3821                else
3822                        savedRays.push_back(*it);
3823        }
3824
3825    if (!mUsePredefinedViewCells)
3826        {
3827                // no view cells loaded
3828                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
3829                // collect final view cells
3830                mBspTree->CollectViewCells(mViewCells);
3831        }
3832        else
3833        {       
3834                // use predefined view cells geometry =>
3835                // contruct bsp hierarchy over them
3836                mBspTree->Construct(mViewCells);
3837        }
3838
3839        // destroy rays created only for construction
3840        CLEAR_CONTAINER(constructionRays);
3841
3842        Debug << mBspTree->GetStatistics() << endl;
3843        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3844
3845        // recast rest of the rays
3846        if (SAMPLE_AFTER_SUBDIVISION)
3847                ComputeSampleContributions(savedRays, true, false);
3848
3849        // real meshes are contructed at this stage
3850        if (0)
3851        {
3852                cout << "finalizing view cells ... ";
3853                FinalizeViewCells(true);
3854                cout << "finished" << endl;     
3855        }
3856
3857        return sampleContributions;
3858}
3859
3860
3861void BspViewCellsManager::CollectViewCells()
3862{       
3863        if (!ViewCellsTreeConstructed())
3864        {       // view cells tree constructed 
3865                mBspTree->CollectViewCells(mViewCells);
3866        }
3867        else
3868        {       // we can use the view cells tree hierarchy to get the right set
3869                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
3870        }
3871}
3872
3873
3874float BspViewCellsManager::GetProbability(ViewCell *viewCell)
3875{
3876        if (1)
3877                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3878        else
3879                // compute view cell area as subsititute for probability
3880                return GetArea(viewCell) / GetAccVcArea();
3881}
3882
3883
3884
3885int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
3886                                                                                 const Vector3 &termination,
3887                                                                                 ViewCellContainer &viewcells)
3888{
3889        return mBspTree->CastLineSegment(origin, termination, viewcells);
3890}
3891
3892
3893bool BspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
3894                                                                                                const Vector3 &termination,
3895                                                                                                ViewCell *viewCell)
3896{
3897        return false;
3898}
3899
3900
3901void ViewCellsManager::ExportMergedViewCells(const ObjectContainer &objects)
3902{
3903        // save color code
3904        const int savedColorCode = mColorCode;
3905
3906        Exporter *exporter;
3907
3908        // export merged view cells using pvs color coding
3909        exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
3910        cout << "exporting view cells after merge (pvs size) ... ";     
3911
3912        if (exporter)
3913        {
3914                if (mExportGeometry)
3915                {
3916                        exporter->ExportGeometry(objects);
3917                }
3918
3919                exporter->SetFilled();
3920                mColorCode = 1;
3921
3922                ExportViewCellsForViz(exporter, NULL,  mColorCode, GetClipPlane());
3923
3924                delete exporter;
3925        }
3926        cout << "finished" << endl;
3927       
3928        mColorCode = savedColorCode;
3929}
3930
3931
3932int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
3933                                                                         const VssRayContainer &rays)
3934{
3935        if (!ViewCellsConstructed())
3936        {
3937                Debug << "view cells not constructed" << endl;
3938                return 0;
3939        }
3940       
3941        // view cells already finished before post processing step,
3942        // i.e., because they were loaded from disc
3943        if (mViewCellsFinished)
3944        {
3945                FinalizeViewCells(true);
3946                EvaluateViewCellsStats();
3947
3948                return 0;
3949        }
3950
3951        //////////////////
3952        //-- merge leaves of the view cell hierarchy   
3953       
3954        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
3955        long startTime = GetTime();
3956       
3957        VssRayContainer postProcessRays;
3958        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3959
3960        if (mMergeViewCells)
3961        {
3962                cout << "constructing visibility based merge tree" << endl;
3963                mViewCellsTree->ConstructMergeTree(rays, objects);
3964        }
3965        else
3966        {
3967                cout << "constructing spatial merge tree" << endl;
3968                ViewCell *root;
3969                // the spatial merge tree is difficult to build for
3970                // this type of construction, as view cells cover several
3971                // leaves => create dummy tree which is only 2 levels deep
3972                if (mUsePredefinedViewCells)
3973                {
3974                        root = ConstructDummyMergeTree(mBspTree->GetRoot());
3975                }
3976                else
3977                {
3978                        // create spatial merge hierarchy
3979                        root = ConstructSpatialMergeTree(mBspTree->GetRoot());
3980                }
3981               
3982                mViewCellsTree->SetRoot(root);
3983
3984                // recompute pvs in the whole hierarchy
3985                ObjectPvs pvs;
3986                UpdatePvsForEvaluation(root, pvs);
3987        }
3988
3989        cout << "finished" << endl;
3990        cout << "merged view cells in "
3991                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
3992
3993        Debug << "Postprocessing: Merged view cells in "
3994                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
3995
3996       
3997        ////////////////////////
3998        //-- visualization and statistics after merge
3999
4000        if (1)
4001        {
4002                char mstats[100];
4003                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
4004                mViewCellsTree->ExportStats(mstats);
4005        }
4006
4007        // recompute view cells and stats
4008        ResetViewCells();
4009        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
4010
4011        //  visualization of the view cells
4012        if (1) ExportMergedViewCells(objects);
4013
4014        // compute final meshes and volume / area
4015        if (1) FinalizeViewCells(true);
4016       
4017        return 0;
4018}
4019
4020
4021BspViewCellsManager::~BspViewCellsManager()
4022{
4023}
4024
4025
4026int BspViewCellsManager::GetType() const
4027{
4028        return BSP;
4029}
4030
4031
4032void BspViewCellsManager::Visualize(const ObjectContainer &objects,
4033                                                                        const VssRayContainer &sampleRays)
4034{
4035        if (!ViewCellsConstructed())
4036                return;
4037       
4038        const int savedColorCode = mColorCode;
4039       
4040        if (1) // export final view cells
4041        {
4042                mColorCode = 1; // 0 = pvs, 1 = random
4043                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4044       
4045                cout << "exporting view cells after merge (pvs size) ... ";     
4046
4047                if (exporter)
4048                {
4049                        if (mExportGeometry)
4050                        {
4051                                exporter->ExportGeometry(objects);
4052                        }
4053
4054                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4055                        delete exporter;
4056                }
4057                cout << "finished" << endl;
4058        }
4059
4060        // reset color code
4061        mColorCode = savedColorCode;
4062
4063
4064        //////////////////
4065        //-- visualization of the BSP splits
4066
4067        bool exportSplits = false;
4068        Environment::GetSingleton()->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
4069
4070        if (exportSplits)
4071        {
4072                cout << "exporting splits ... ";
4073                ExportSplits(objects);
4074                cout << "finished" << endl;
4075        }
4076
4077        int leafOut;
4078        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4079        const int raysOut = 100;
4080        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
4081}
4082
4083
4084void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
4085{
4086        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4087
4088        if (exporter)
4089        {
4090                //exporter->SetFilled();
4091                if (mExportGeometry)
4092                {
4093                        exporter->ExportGeometry(objects);
4094                }
4095
4096                Material m;
4097                m.mDiffuseColor = RgbColor(1, 0, 0);
4098                exporter->SetForcedMaterial(m);
4099                exporter->SetWireframe();
4100
4101                exporter->ExportBspSplits(*mBspTree, true);
4102
4103                // NOTE: take forced material, else big scenes cannot be viewed
4104                m.mDiffuseColor = RgbColor(0, 1, 0);
4105                exporter->SetForcedMaterial(m);
4106                //exporter->ResetForcedMaterial();
4107
4108                delete exporter;
4109        }
4110}
4111
4112
4113void BspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4114                                                                                                const int maxViewCells,
4115                                                                                                const bool sortViewCells,
4116                                                                                                const bool exportPvs,
4117                                                                                                const bool exportRays,
4118                                                                                                const int maxRays,
4119                                                                                                const string &prefix,
4120                                                                                                VssRayContainer *visRays)
4121{
4122        if (sortViewCells)
4123        {       // sort view cells to visualize the largest view cells
4124                sort(mViewCells.begin(), mViewCells.end(), LargerRenderCost);
4125        }
4126
4127        //////////
4128        //-- export visualizations of some view cells
4129
4130        ViewCell::NewMail();
4131        const int limit = min(maxViewCells, (int)mViewCells.size());
4132       
4133        for (int i = 0; i < limit; ++ i)
4134        {
4135                const int idx = sortViewCells ? (int)RandomValue(0, (float)mViewCells.size() - 0.5f) : i;
4136                ViewCell *vc = mViewCells[idx];
4137
4138                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
4139                        continue;
4140
4141                vc->Mail();
4142
4143                ObjectPvs pvs;
4144                mViewCellsTree->GetPvs(vc, pvs);
4145
4146                char s[64]; sprintf(s, "%sviewcell-%04d.wrl", prefix.c_str(), i);
4147                Exporter *exporter = Exporter::GetExporter(s);
4148               
4149                cout << "view cell " << idx << ": pvs cost=" << (int)mViewCellsTree->GetTrianglesInPvs(vc) << endl;
4150
4151                if (exportRays)
4152                {
4153                        ////////////
4154                        //-- export rays piercing this view cell
4155
4156                        // use rays stored with the view cells
4157                        VssRayContainer vcRays, vcRays2, vcRays3;
4158            VssRayContainer collectRays;
4159
4160                        // collect initial view cells
4161                        ViewCellContainer leaves;
4162                        mViewCellsTree->CollectLeaves(vc, leaves);
4163
4164                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4165                for (vit = leaves.begin(); vit != vit_end; ++ vit)
4166                        {       
4167                                // prepare some rays for visualization
4168                                VssRayContainer::const_iterator rit, rit_end = (*vit)->GetOrCreateRays()->end();
4169                                for (rit = (*vit)->GetOrCreateRays()->begin(); rit != rit_end; ++ rit)
4170                                {
4171                                        collectRays.push_back(*rit);
4172                                }
4173                        }
4174
4175                        const int raysOut = min((int)collectRays.size(), maxRays);
4176
4177                        // prepare some rays for visualization
4178                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4179                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4180                        {
4181                                const float p = RandomValue(0.0f, (float)collectRays.size());
4182                                if (p < raysOut)
4183                                {
4184                                        if ((*rit)->mFlags & VssRay::BorderSample)
4185                                        {
4186                                                vcRays.push_back(*rit);
4187                                        }
4188                                        else if ((*rit)->mFlags & VssRay::ReverseSample)
4189                                        {
4190                                                vcRays2.push_back(*rit);
4191                                        }
4192                                        else
4193                                        {
4194                                                vcRays3.push_back(*rit);
4195                                        }       
4196                                }
4197                        }
4198
4199                        exporter->ExportRays(vcRays, RgbColor(1, 0, 0));
4200                        exporter->ExportRays(vcRays2, RgbColor(0, 1, 0));
4201                        exporter->ExportRays(vcRays3, RgbColor(1, 1, 1));
4202                }
4203               
4204                ////////////////
4205                //-- export view cell geometry
4206
4207                exporter->SetWireframe();
4208
4209                Material m;//= RandomMaterial();
4210                m.mDiffuseColor = RgbColor(0, 1, 0);
4211                exporter->SetForcedMaterial(m);
4212
4213                ExportViewCellGeometry(exporter, vc, NULL, NULL);
4214                exporter->SetFilled();
4215
4216                if (exportPvs)
4217                {
4218                        Intersectable::NewMail();
4219                        ObjectPvsIterator pit = pvs.GetIterator();
4220
4221                        while (pit.HasMoreEntries())
4222                        {               
4223                                Intersectable *intersect = pit.Next();
4224
4225                // output PVS of view cell
4226                                if (!intersect->Mailed())
4227                                {
4228                                        intersect->Mail();
4229
4230                                        m = RandomMaterial();
4231                                        exporter->SetForcedMaterial(m);
4232                                        exporter->ExportIntersectable(intersect);
4233                                }
4234                        }
4235                        cout << endl;
4236                }
4237               
4238                DEL_PTR(exporter);
4239                cout << "finished" << endl;
4240        }
4241}
4242
4243
4244void BspViewCellsManager::TestSubdivision()
4245{
4246        ViewCellContainer leaves;
4247        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
4248
4249        ViewCellContainer::const_iterator it, it_end = leaves.end();
4250
4251        const float vol = mViewSpaceBox.GetVolume();
4252        float subdivVol = 0;
4253        float newVol = 0;
4254
4255        for (it = leaves.begin(); it != it_end; ++ it)
4256        {
4257                BspNodeGeometry geom;
4258                mBspTree->ConstructGeometry(*it, geom);
4259
4260                const float lVol = geom.GetVolume();
4261                newVol += lVol;
4262                subdivVol += (*it)->GetVolume();
4263
4264                const float thres = 0.9f;
4265                if ((lVol < ((*it)->GetVolume() * thres)) ||
4266                        (lVol * thres > ((*it)->GetVolume())))
4267                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
4268        }
4269       
4270        Debug << "exact volume: " << vol << endl;
4271        Debug << "subdivision volume: " << subdivVol << endl;
4272        Debug << "new volume: " << newVol << endl;
4273}
4274
4275
4276void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4277                                                                                                 ViewCell *vc,
4278                                                                                                 const AxisAlignedBox3 *sceneBox,
4279                                                                                                 const AxisAlignedPlane *clipPlane
4280                                                                                                 ) const
4281{
4282        if (clipPlane)
4283        {
4284                const Plane3 plane = clipPlane->GetPlane();
4285
4286                ViewCellContainer leaves;
4287                mViewCellsTree->CollectLeaves(vc, leaves);
4288                ViewCellContainer::const_iterator it, it_end = leaves.end();
4289
4290                for (it = leaves.begin(); it != it_end; ++ it)
4291                {
4292                        BspNodeGeometry geom;
4293                        BspNodeGeometry front;
4294                        BspNodeGeometry back;
4295
4296                        mBspTree->ConstructGeometry(*it, geom);
4297
4298                        const float eps = 0.0001f;
4299                        const int cf = geom.Side(plane, eps);
4300
4301                        if (cf == -1)
4302                        {
4303                                exporter->ExportPolygons(geom.GetPolys());
4304                        }
4305                        else if (cf == 0)
4306                        {
4307                                geom.SplitGeometry(front,
4308                                                                   back,
4309                                                                   plane,
4310                                                                   mViewSpaceBox,
4311                                                                   eps);
4312
4313                                if (back.Valid())
4314                                {
4315                                        exporter->ExportPolygons(back.GetPolys());
4316                                }                       
4317                        }
4318                }
4319        }
4320        else
4321        {
4322                // export mesh if available
4323                // TODO: some bug here?
4324                if (1 && vc->GetMesh())
4325                {
4326                        exporter->ExportMesh(vc->GetMesh());
4327                }
4328                else
4329                {
4330                        BspNodeGeometry geom;
4331                        mBspTree->ConstructGeometry(vc, geom);
4332                        exporter->ExportPolygons(geom.GetPolys());
4333                }
4334        }
4335}
4336
4337
4338void BspViewCellsManager::CreateMesh(ViewCell *vc)
4339{
4340        // note: should previous mesh be deleted (via mesh manager?)
4341        BspNodeGeometry geom;
4342        mBspTree->ConstructGeometry(vc, geom);
4343
4344        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
4345       
4346        IncludeNodeGeomInMesh(geom, *mesh);
4347        mesh->ComputeBoundingBox();
4348
4349        vc->SetMesh(mesh);
4350}
4351
4352
4353void BspViewCellsManager::Finalize(ViewCell *viewCell,
4354                                                                   const bool createMesh)
4355{
4356        float area = 0;
4357        float volume = 0;
4358
4359        ViewCellContainer leaves;
4360        mViewCellsTree->CollectLeaves(viewCell, leaves);
4361
4362        ViewCellContainer::const_iterator it, it_end = leaves.end();
4363
4364    for (it = leaves.begin(); it != it_end; ++ it)
4365        {
4366                BspNodeGeometry geom;
4367
4368                mBspTree->ConstructGeometry(*it, geom);
4369
4370                const float lVol = geom.GetVolume();
4371                const float lArea = geom.GetArea();
4372
4373                area += lArea;
4374                volume += lVol;
4375       
4376                CreateMesh(*it);
4377        }
4378
4379        viewCell->SetVolume(volume);
4380        viewCell->SetArea(area);
4381}
4382
4383
4384ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
4385{
4386        if (!ViewCellsConstructed())
4387        {
4388                return NULL;
4389        }
4390        if (!mViewSpaceBox.IsInside(point))
4391        {
4392                return NULL;
4393        }
4394        return mBspTree->GetViewCell(point);
4395}
4396
4397
4398void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4399                                                                                                 vector<MergeCandidate> &candidates)
4400{
4401        cout << "collecting merge candidates ... " << endl;
4402
4403        if (mUseRaysForMerge)
4404        {
4405                mBspTree->CollectMergeCandidates(rays, candidates);
4406        }
4407        else
4408        {
4409                vector<BspLeaf *> leaves;
4410                mBspTree->CollectLeaves(leaves);
4411                mBspTree->CollectMergeCandidates(leaves, candidates);
4412        }
4413
4414        cout << "fininshed collecting candidates" << endl;
4415}
4416
4417
4418
4419bool BspViewCellsManager::ExportViewCells(const string filename,
4420                                                                                  const bool exportPvs,
4421                                                                                  const ObjectContainer &objects)
4422{
4423        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
4424        {
4425                return false;
4426        }
4427
4428        cout << "exporting view cells to xml ... ";
4429
4430        OUT_STREAM stream(filename.c_str());
4431
4432        // we need unique ids for each view cell
4433        CreateUniqueViewCellIds();
4434
4435        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
4436        stream << "<VisibilitySolution>" << endl;
4437
4438        if (exportPvs)
4439        {
4440                //////////
4441                //-- export bounding boxes: they are used to identify the objects from the pvs and
4442                //-- assign them to the entities in the rendering engine
4443
4444                stream << "<BoundingBoxes>" << endl;
4445                ObjectContainer::const_iterator oit, oit_end = objects.end();
4446
4447                for (oit = objects.begin(); oit != oit_end; ++ oit)
4448                {
4449                        const AxisAlignedBox3 box = (*oit)->GetBox();
4450                       
4451                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
4452                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
4453                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
4454                }
4455
4456                stream << "</BoundingBoxes>" << endl;
4457        }
4458
4459        ///////////
4460        //-- export the view cells and the pvs
4461
4462        const int numViewCells = mCurrentViewCellsStats.viewCells;
4463        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
4464
4465        mViewCellsTree->Export(stream, exportPvs);
4466       
4467        stream << "</ViewCells>" << endl;
4468
4469        /////////////
4470        //-- export the view space hierarchy
4471        stream << "<ViewSpaceHierarchy type=\"bsp\""
4472                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
4473                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
4474
4475        mBspTree->Export(stream);
4476
4477        // end tags
4478        stream << "</ViewSpaceHierarchy>" << endl;
4479        stream << "</VisibilitySolution>" << endl;
4480
4481        stream.close();
4482        cout << "finished" << endl;
4483
4484        return true;
4485}
4486
4487
4488ViewCell *BspViewCellsManager::ConstructDummyMergeTree(BspNode *root)
4489{
4490        ViewCellInterior *vcRoot = new ViewCellInterior();
4491               
4492        // evaluate merge cost for priority traversal
4493        const float mergeCost =  -(float)root->mTimeStamp;
4494        vcRoot->SetMergeCost(mergeCost);
4495
4496        float volume = 0;
4497        vector<BspLeaf *> leaves;
4498        mBspTree->CollectLeaves(leaves);
4499        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
4500        ViewCell::NewMail();
4501
4502        for (lit = leaves.begin(); lit != lit_end; ++ lit)
4503        {
4504                BspLeaf *leaf = *lit;
4505                ViewCell *vc = leaf->GetViewCell();
4506
4507                if (!vc->Mailed())
4508                {
4509                        vc->Mail();
4510                        vc->SetMergeCost(0.0f);
4511                        vcRoot->SetupChildLink(vc);
4512
4513                        volume += vc->GetVolume();
4514                        volume += vc->GetVolume();     
4515                        vcRoot->SetVolume(volume);
4516                }
4517        }
4518       
4519        return vcRoot;
4520}
4521
4522
4523ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4524{
4525        // terminate recursion
4526        if (root->IsLeaf())
4527        {
4528                BspLeaf *leaf = static_cast<BspLeaf *>(root);
4529                leaf->GetViewCell()->SetMergeCost(0.0f);
4530                return leaf->GetViewCell();
4531        }
4532       
4533        BspInterior *interior = static_cast<BspInterior *>(root);
4534        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4535               
4536        // evaluate merge cost for priority traversal
4537        const float mergeCost = -(float)root->mTimeStamp;
4538        viewCellInterior->SetMergeCost(mergeCost);
4539
4540        float volume = 0;
4541       
4542        BspNode *front = interior->GetFront();
4543        BspNode *back = interior->GetBack();
4544
4545
4546        ////////////
4547        //-- recursivly compute child hierarchies
4548
4549        ViewCell *backVc = ConstructSpatialMergeTree(back);
4550        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4551
4552        viewCellInterior->SetupChildLink(backVc);
4553        viewCellInterior->SetupChildLink(frontVc);
4554
4555        volume += backVc->GetVolume();
4556        volume += frontVc->GetVolume();
4557
4558        viewCellInterior->SetVolume(volume);
4559
4560        return viewCellInterior;
4561}
4562
4563
4564/************************************************************************/
4565/*                   KdViewCellsManager implementation                  */
4566/************************************************************************/
4567
4568
4569
4570KdViewCellsManager::KdViewCellsManager(ViewCellsTree *vcTree, KdTree *kdTree):
4571ViewCellsManager(vcTree), mKdTree(kdTree), mKdPvsDepth(100)
4572{
4573}
4574
4575
4576float KdViewCellsManager::GetProbability(ViewCell *viewCell)
4577{
4578        // compute view cell area / volume as subsititute for probability
4579        if (0)
4580                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
4581        else
4582                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
4583}
4584
4585
4586
4587
4588void KdViewCellsManager::CollectViewCells()
4589{
4590        //mKdTree->CollectViewCells(mViewCells); TODO
4591}
4592
4593
4594int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4595                                                                  const VssRayContainer &rays)
4596{
4597        // if view cells already constructed
4598        if (ViewCellsConstructed())
4599                return 0;
4600
4601        mKdTree->Construct();
4602
4603        mTotalAreaValid = false;
4604        // create the view cells
4605        mKdTree->CreateAndCollectViewCells(mViewCells);
4606        // cast rays
4607        ComputeSampleContributions(rays, true, false);
4608
4609        EvaluateViewCellsStats();
4610        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4611
4612        return 0;
4613}
4614
4615
4616bool KdViewCellsManager::ViewCellsConstructed() const
4617{
4618        return mKdTree->GetRoot() != NULL;
4619}
4620
4621
4622int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
4623                                                                        const VssRayContainer &rays)
4624{
4625        return 0;
4626}
4627
4628
4629void KdViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4630                                                                                           const int maxViewCells,
4631                                                                                           const bool sortViewCells,
4632                                                                                           const bool exportPvs,
4633                                                                                           const bool exportRays,
4634                                                                                           const int maxRays,
4635                                                                                           const string &prefix,
4636                                                                                           VssRayContainer *visRays)
4637{
4638        // TODO
4639}
4640
4641
4642void KdViewCellsManager::Visualize(const ObjectContainer &objects,
4643                                                                   const VssRayContainer &sampleRays)
4644{
4645        if (!ViewCellsConstructed())
4646                return;
4647
4648        // using view cells instead of the kd PVS of objects
4649        const bool useViewCells = true;
4650        bool exportRays = false;
4651
4652        int limit = min(mVisualizationSamples, (int)sampleRays.size());
4653        const int pvsOut = min((int)objects.size(), 10);
4654        VssRayContainer *rays = new VssRayContainer[pvsOut];
4655
4656        if (useViewCells)
4657        {
4658                const int leafOut = 10;
4659
4660                ViewCell::NewMail();
4661
4662                //-- some rays for visualization
4663                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
4664                Debug << "visualization using " << raysOut << " samples" << endl;
4665
4666                //-- some random view cells and rays for visualization
4667                vector<KdLeaf *> kdLeaves;
4668
4669                for (int i = 0; i < leafOut; ++ i)
4670                        kdLeaves.push_back(static_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
4671
4672                for (int i = 0; i < kdLeaves.size(); ++ i)
4673                {
4674                        KdLeaf *leaf = kdLeaves[i];
4675                        RayContainer vcRays;
4676
4677                        cout << "creating output for view cell " << i << " ... ";
4678#if 0
4679                        // check whether we can add the current ray to the output rays
4680                        for (int k = 0; k < raysOut; ++ k)
4681                        {
4682                                Ray *ray = sampleRays[k];
4683
4684                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
4685                                {
4686                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
4687
4688                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
4689                                        {
4690                                                vcRays.push_back(ray);
4691                                        }
4692                                }
4693                        }
4694#endif
4695                        Intersectable::NewMail();
4696
4697                        ViewCell *vc = leaf->mViewCell;
4698                        char str[64]; sprintf(str, "viewcell%04d.wrl", i);
4699
4700                        Exporter *exporter = Exporter::GetExporter(str);
4701                        exporter->SetFilled();
4702
4703                        exporter->SetWireframe();
4704                        //exporter->SetFilled();
4705
4706                        Material m;//= RandomMaterial();
4707                        m.mDiffuseColor = RgbColor(1, 1, 0);
4708                        exporter->SetForcedMaterial(m);
4709
4710                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
4711                        exporter->ExportBox(box);
4712
4713                        // export rays piercing this view cell
4714                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
4715
4716                        m.mDiffuseColor = RgbColor(1, 0, 0);
4717                        exporter->SetForcedMaterial(m);
4718
4719                        // exporter->SetWireframe();
4720                        exporter->SetFilled();
4721
4722                        ObjectPvsIterator pit = vc->GetPvs().GetIterator();
4723                       
4724                        while (pit.HasMoreEntries())
4725                        {               
4726                                //-- output PVS of view cell
4727                                Intersectable *intersect = pit.Next();
4728
4729                                if (!intersect->Mailed())
4730                                {
4731                                        exporter->ExportIntersectable(intersect);
4732                                        intersect->Mail();
4733                                }
4734                        }
4735
4736                        DEL_PTR(exporter);
4737                        cout << "finished" << endl;
4738                }
4739
4740                DEL_PTR(rays);
4741        }
4742        else // using kd PVS of objects
4743        {
4744                for (int i = 0; i < limit; ++ i)
4745                {
4746                        VssRay *ray = sampleRays[i];
4747
4748                        // check whether we can add this to the rays
4749                        for (int j = 0; j < pvsOut; j++)
4750                        {
4751                                if (objects[j] == ray->mTerminationObject)
4752                                {
4753                                        rays[j].push_back(ray);
4754                                }
4755                        }
4756                }
4757
4758                if (exportRays)
4759                {
4760                        Exporter *exporter = NULL;
4761                        exporter = Exporter::GetExporter("sample-rays.x3d");
4762                        exporter->SetWireframe();
4763                        exporter->ExportKdTree(*mKdTree);
4764
4765                        for (int i = 0; i < pvsOut; i++)
4766                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
4767
4768                        exporter->SetFilled();
4769                        delete exporter;
4770                }
4771
4772                for (int k=0; k < pvsOut; k++)
4773                {
4774                        Intersectable *object = objects[k];
4775                        char str[64]; sprintf(str, "viewcell%04d.wrl", k);
4776
4777                        Exporter *exporter = Exporter::GetExporter(str);
4778                        exporter->SetWireframe();
4779
4780                        // matt: we do not use kd pvs
4781#if 0
4782                        KdPvsMap::iterator kit = object->mKdPvs.mEntries.begin();
4783                        Intersectable::NewMail();
4784
4785                        // avoid adding the object to the list
4786                        object->Mail();
4787                        ObjectContainer visibleObjects;
4788
4789                        for (; kit != object->mKdPvs.mEntries.end(); i++)
4790                        {
4791                                KdNode *node = (*kit).first;
4792                                exporter->ExportBox(mKdTree->GetBox(node));
4793
4794                                mKdTree->CollectObjects(node, visibleObjects);
4795                        }
4796
4797                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
4798                        exporter->SetFilled();
4799
4800                        for (int j = 0; j < visibleObjects.size(); j++)
4801                                exporter->ExportIntersectable(visibleObjects[j]);
4802
4803                        Material m;
4804                        m.mDiffuseColor = RgbColor(1, 0, 0);
4805                        exporter->SetForcedMaterial(m);
4806                        exporter->ExportIntersectable(object);
4807#endif
4808                        delete exporter;
4809                }
4810        }
4811}
4812
4813
4814ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
4815{
4816        return new KdViewCell(mesh);
4817}
4818
4819
4820void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4821                                                                                                ViewCell *vc,
4822                                                                                                const AxisAlignedBox3 *sceneBox,
4823                                                                                                const AxisAlignedPlane *clipPlane
4824                                                                                                ) const
4825{
4826        ViewCellContainer leaves;
4827        mViewCellsTree->CollectLeaves(vc, leaves);
4828        ViewCellContainer::const_iterator it, it_end = leaves.end();
4829
4830        for (it = leaves.begin(); it != it_end; ++ it)
4831        {
4832                KdViewCell *kdVc = static_cast<KdViewCell *>(*it);
4833                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaves[0]));
4834        }
4835}
4836
4837
4838int KdViewCellsManager::GetType() const
4839{
4840        return ViewCellsManager::KD;
4841}
4842
4843
4844
4845KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
4846{
4847        KdNode *node = leaf;
4848
4849        while (node->mParent && node->mDepth > mKdPvsDepth)
4850                node = node->mParent;
4851
4852        return node;
4853}
4854
4855int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
4856                                                                                const Vector3 &termination,
4857                                                                                ViewCellContainer &viewcells)
4858{
4859        return mKdTree->CastLineSegment(origin, termination, viewcells);
4860}
4861
4862
4863bool KdViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
4864                                                                                           const Vector3 &termination,
4865                                                                                           ViewCell *viewCell)
4866{
4867        return false;
4868}
4869
4870
4871void KdViewCellsManager::CreateMesh(ViewCell *vc)
4872{
4873        // TODO
4874}
4875
4876
4877
4878void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4879                                                                                                vector<MergeCandidate> &candidates)
4880{
4881        // TODO
4882}
4883
4884
4885
4886/**************************************************************************/
4887/*                   VspBspViewCellsManager implementation                */
4888/**************************************************************************/
4889
4890
4891VspBspViewCellsManager::VspBspViewCellsManager(ViewCellsTree *vcTree, VspBspTree *vspBspTree):
4892ViewCellsManager(vcTree), mVspBspTree(vspBspTree)
4893{
4894        Environment::GetSingleton()->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
4895        mVspBspTree->SetViewCellsManager(this);
4896        mVspBspTree->mViewCellsTree = mViewCellsTree;
4897}
4898
4899
4900VspBspViewCellsManager::~VspBspViewCellsManager()
4901{
4902}
4903
4904
4905float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
4906{
4907        if (0 && mVspBspTree->mUseAreaForPvs)
4908                return GetArea(viewCell) / GetAccVcArea();
4909        else
4910                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
4911}
4912
4913
4914void VspBspViewCellsManager::CollectViewCells()
4915{
4916        // view cells tree constructed?
4917        if (!ViewCellsTreeConstructed())
4918        {
4919                mVspBspTree->CollectViewCells(mViewCells, false);
4920        }
4921        else
4922        {       
4923                // we can use the view cells tree hierarchy to get the right set
4924                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
4925        }
4926}
4927
4928
4929void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4930                                                                                                        vector<MergeCandidate> &candidates)
4931{       
4932        cout << "collecting merge candidates ... " << endl;
4933
4934        if (mUseRaysForMerge)
4935        {
4936                mVspBspTree->CollectMergeCandidates(rays, candidates);
4937        }
4938        else
4939        {
4940                vector<BspLeaf *> leaves;
4941                mVspBspTree->CollectLeaves(leaves);
4942       
4943                mVspBspTree->CollectMergeCandidates(leaves, candidates);
4944        }
4945
4946        cout << "fininshed collecting candidates" << endl;
4947}
4948
4949
4950bool VspBspViewCellsManager::ViewCellsConstructed() const
4951{
4952        return mVspBspTree->GetRoot() != NULL;
4953}
4954
4955
4956ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
4957{
4958        return new BspViewCell(mesh);
4959}
4960
4961
4962int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4963                                                                                                 const VssRayContainer &rays)
4964{
4965        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
4966
4967        // if view cells were already constructed
4968        if (ViewCellsConstructed())
4969        {
4970                return 0;
4971        }
4972
4973        int sampleContributions = 0;
4974        VssRayContainer sampleRays;
4975
4976        const int limit = min(mInitialSamples, (int)rays.size());
4977
4978        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
4979                  << ", actual rays: " << (int)rays.size() << endl;
4980
4981        VssRayContainer savedRays;
4982
4983        if (SAMPLE_AFTER_SUBDIVISION)
4984        {
4985                VssRayContainer constructionRays;
4986               
4987                GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
4988
4989                Debug << "rays used for initial construction: " << (int)constructionRays.size() << endl;
4990                Debug << "rays saved for later use: " << (int)savedRays.size() << endl;
4991       
4992                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
4993        }
4994        else
4995        {
4996                Debug << "rays used for initial construction: " << (int)rays.size() << endl;
4997                mVspBspTree->Construct(rays, &mViewSpaceBox);
4998        }
4999
5000        // collapse invalid regions
5001        cout << "collapsing invalid tree regions ... ";
5002        long startTime = GetTime();
5003
5004        const int collapsedLeaves = mVspBspTree->CollapseTree();
5005        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
5006                  << " seconds" << endl;
5007
5008    cout << "finished" << endl;
5009
5010        /////////////////
5011        //-- stats after construction
5012
5013        Debug << mVspBspTree->GetStatistics() << endl;
5014
5015        ResetViewCells();
5016        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
5017
5018
5019        //////////////////////
5020        //-- recast the rest of the rays
5021
5022        startTime = GetTime();
5023
5024        cout << "Computing remaining ray contributions ... ";
5025
5026        if (SAMPLE_AFTER_SUBDIVISION)
5027                ComputeSampleContributions(savedRays, true, false);
5028
5029        cout << "finished" << endl;
5030
5031        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
5032                  << " secs" << endl;
5033
5034        cout << "construction finished" << endl;
5035
5036        if (0)
5037        {       ////////
5038                //-- real meshes are contructed at this stage
5039
5040                cout << "finalizing view cells ... ";
5041                FinalizeViewCells(true);
5042                cout << "finished" << endl;
5043        }
5044
5045        return sampleContributions;
5046}
5047
5048
5049void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
5050                                                                                        const ObjectContainer &objects)
5051{
5052    int vcSize = 0;
5053        int pvsSize = 0;
5054
5055        //-- merge view cells
5056        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
5057        long startTime = GetTime();
5058
5059
5060        if (mMergeViewCells)
5061        {
5062                // TODO: should be done BEFORE the ray casting
5063                // compute tree by merging the nodes based on cost heuristics
5064                mViewCellsTree->ConstructMergeTree(rays, objects);
5065        }
5066        else
5067        {
5068                // compute tree by merging the nodes of the spatial hierarchy
5069                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
5070                mViewCellsTree->SetRoot(root);
5071
5072                // compute pvs
5073                ObjectPvs pvs;
5074                UpdatePvsForEvaluation(root, pvs);
5075        }
5076
5077        if (1)
5078        {
5079                char mstats[100];
5080                ObjectPvs pvs;
5081
5082                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
5083                mViewCellsTree->ExportStats(mstats);
5084        }
5085
5086        cout << "merged view cells in "
5087                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
5088
5089        Debug << "Postprocessing: Merged view cells in "
5090                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
5091       
5092
5093        //////////////////
5094        //-- stats and visualizations
5095
5096        int savedColorCode = mColorCode;
5097       
5098        // get currently active view cell set
5099        ResetViewCells();
5100        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
5101       
5102        if (mShowVisualization) // export merged view cells
5103        {
5104                mColorCode = 0;
5105                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
5106               
5107                cout << "exporting view cells after merge ... ";
5108
5109                if (exporter)
5110                {
5111                        if (0)
5112                                exporter->SetWireframe();
5113                        else
5114                                exporter->SetFilled();
5115
5116                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5117
5118                        if (mExportGeometry)
5119                        {
5120                                Material m;
5121                                m.mDiffuseColor = RgbColor(0, 1, 0);
5122                                exporter->SetForcedMaterial(m);
5123                                exporter->SetFilled();
5124
5125                                exporter->ExportGeometry(objects);
5126                        }
5127
5128                        delete exporter;
5129                }
5130                cout << "finished" << endl;
5131        }
5132
5133        mColorCode = savedColorCode;
5134}
5135
5136
5137void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
5138                                                                                         const ObjectContainer &objects)
5139{
5140        mRenderer->RenderScene();
5141
5142        SimulationStatistics ss;
5143        static_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5144    Debug << "render time before refine\n\n" << ss << endl;
5145
5146        const long startTime = GetTime();
5147        cout << "Refining the merged view cells ... ";
5148
5149        // refining the merged view cells
5150        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
5151
5152        //-- stats and visualizations
5153        cout << "finished" << endl;
5154        cout << "refined " << refined << " view cells in "
5155                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
5156
5157        Debug << "Postprocessing: refined " << refined << " view cells in "
5158                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
5159}
5160
5161
5162int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
5163                                                                                const VssRayContainer &rays)
5164{
5165        if (!ViewCellsConstructed())
5166        {
5167                Debug << "postprocess error: no view cells constructed" << endl;
5168                return 0;
5169        }
5170
5171        // view cells already finished before post processing step
5172        // (i.e. because they were loaded)
5173        if (mViewCellsFinished)
5174        {
5175                FinalizeViewCells(true);
5176                EvaluateViewCellsStats();
5177
5178                return 0;
5179        }
5180
5181        // check if new view cells turned invalid
5182        int minPvs, maxPvs;
5183
5184        if (0)
5185        {
5186                minPvs = mMinPvsSize;
5187                maxPvs = mMaxPvsSize;
5188        }
5189        else
5190        {
5191                // problem matt: why did I start here from zero?
5192                minPvs = 0;
5193                maxPvs = mMaxPvsSize;
5194        }
5195
5196        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5197        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5198       
5199        SetValidity(minPvs, maxPvs);
5200
5201        // update valid view space according to valid view cells
5202        if (0) mVspBspTree->ValidateTree();
5203
5204        // area has to be recomputed
5205        mTotalAreaValid = false;
5206        VssRayContainer postProcessRays;
5207        GetRaySets(rays, mPostProcessSamples, postProcessRays);
5208
5209        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
5210
5211        //////////
5212        //-- merge neighbouring view cells
5213        MergeViewCells(postProcessRays, objects);
5214       
5215        // refines the merged view cells
5216        if (0) RefineViewCells(postProcessRays, objects);
5217
5218
5219        ///////////
5220        //-- render simulation after merge + refine
5221
5222        cout << "\nview cells partition render time before compress" << endl << endl;;
5223        static_cast<RenderSimulator *>(mRenderer)->RenderScene();
5224        SimulationStatistics ss;
5225        static_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5226        cout << ss << endl;
5227       
5228        if (0) CompressViewCells();
5229       
5230        // collapse sibling leaves that share the same view cell
5231        if (0) mVspBspTree->CollapseTree();
5232
5233        // recompute view cell list and statistics
5234        ResetViewCells();
5235
5236        // compute final meshes and volume / area
5237        if (1) FinalizeViewCells(true);
5238
5239        return 0;
5240}
5241
5242
5243int VspBspViewCellsManager::GetType() const
5244{
5245        return VSP_BSP;
5246}
5247
5248
5249ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
5250{
5251        // terminate recursion
5252        if (root->IsLeaf())
5253        {
5254                BspLeaf *leaf = static_cast<BspLeaf *>(root);
5255                leaf->GetViewCell()->SetMergeCost(0.0f);
5256                return leaf->GetViewCell();
5257        }
5258       
5259       
5260        BspInterior *interior = static_cast<BspInterior *>(root);
5261        ViewCellInterior *viewCellInterior = new ViewCellInterior();
5262               
5263        // evaluate merge cost for priority traversal
5264        float mergeCost = 1.0f / (float)root->mTimeStamp;
5265        viewCellInterior->SetMergeCost(mergeCost);
5266
5267        float volume = 0;
5268       
5269        BspNode *front = interior->GetFront();
5270        BspNode *back = interior->GetBack();
5271
5272
5273        ObjectPvs frontPvs, backPvs;
5274
5275        //-- recursivly compute child hierarchies
5276        ViewCell *backVc = ConstructSpatialMergeTree(back);
5277        ViewCell *frontVc = ConstructSpatialMergeTree(front);
5278
5279
5280        viewCellInterior->SetupChildLink(backVc);
5281        viewCellInterior->SetupChildLink(frontVc);
5282
5283        volume += backVc->GetVolume();
5284        volume += frontVc->GetVolume();
5285
5286        viewCellInterior->SetVolume(volume);
5287
5288        return viewCellInterior;
5289}
5290
5291
5292bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
5293{
5294        if (!ViewCellsConstructed())
5295                return ViewCellsManager::GetViewPoint(viewPoint);
5296
5297        // TODO: set reasonable limit
5298        const int limit = 20;
5299
5300        for (int i = 0; i < limit; ++ i)
5301        {
5302                viewPoint = mViewSpaceBox.GetRandomPoint();
5303                if (mVspBspTree->ViewPointValid(viewPoint))
5304                {
5305                        return true;
5306                }
5307        }
5308
5309        Debug << "failed to find valid view point, taking " << viewPoint << endl;
5310        return false;
5311}
5312
5313
5314bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5315{
5316        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5317        // validy update in preprocessor for all managers)
5318        return ViewCellsManager::ViewPointValid(viewPoint);
5319
5320        //      return mViewSpaceBox.IsInside(viewPoint) &&
5321        //                 mVspBspTree->ViewPointValid(viewPoint);
5322}
5323
5324
5325void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
5326                                                                           const VssRayContainer &sampleRays)
5327{
5328        if (!ViewCellsConstructed())
5329                return;
5330
5331        VssRayContainer visRays;
5332        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5333       
5334        if (1)
5335        {       
5336                //////////////////
5337                //-- export final view cell partition
5338
5339                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5340               
5341                if (exporter)
5342                {
5343                        cout << "exporting view cells after post process ... ";
5344
5345                        if (0)
5346                        {       // export view space box
5347                                exporter->SetWireframe();
5348                                exporter->ExportBox(mViewSpaceBox);
5349                                exporter->SetFilled();
5350                        }
5351
5352                        Material m;
5353                        m.mDiffuseColor.r = 0.0f;
5354                        m.mDiffuseColor.g = 0.5f;
5355                        m.mDiffuseColor.b = 0.5f;
5356
5357            exporter->SetForcedMaterial(m);
5358
5359                        if (1 && mExportGeometry)
5360                        {
5361                                exporter->ExportGeometry(objects);
5362                        }
5363
5364                        if (0 && mExportRays)
5365                        {
5366                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
5367                        }
5368                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5369
5370                        delete exporter;
5371                        cout << "finished" << endl;
5372                }
5373        }
5374
5375        ////////////////
5376        //-- visualization of the BSP splits
5377
5378        bool exportSplits = false;
5379        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
5380
5381        if (exportSplits)
5382        {
5383                cout << "exporting splits ... ";
5384                ExportSplits(objects, visRays);
5385                cout << "finished" << endl;
5386        }
5387
5388        ////////
5389        //-- export single view cells
5390       
5391        int leafOut;
5392        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5393        const int raysOut = 100;
5394       
5395        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
5396}
5397
5398
5399void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
5400                                                                                  const VssRayContainer &rays)
5401{
5402        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
5403
5404        if (exporter)
5405        {
5406                Material m;
5407                m.mDiffuseColor = RgbColor(1, 0, 0);
5408                exporter->SetForcedMaterial(m);
5409                exporter->SetWireframe();
5410
5411                exporter->ExportBspSplits(*mVspBspTree, true);
5412
5413                // take forced material, else big scenes cannot be viewed
5414                m.mDiffuseColor = RgbColor(0, 1, 0);
5415                exporter->SetForcedMaterial(m);
5416                exporter->SetFilled();
5417
5418                exporter->ResetForcedMaterial();
5419
5420                // export rays
5421                if (mExportRays)
5422                {
5423                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
5424                }
5425
5426                if (mExportGeometry)
5427                {
5428                        exporter->ExportGeometry(objects);
5429                }
5430                delete exporter;
5431        }
5432}
5433
5434
5435void VspBspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
5436                                                                                                   const int maxViewCells,
5437                                                                                                   const bool sortViewCells,
5438                                                                                                   const bool exportPvs,
5439                                                                                                   const bool exportRays,
5440                                                                                                   const int maxRays,
5441                                                                                                   const string &prefix,
5442                                                                                                   VssRayContainer *visRays)
5443{       
5444        if (sortViewCells)
5445        {
5446                // sort view cells to visualize the largest view cells
5447                sort(mViewCells.begin(), mViewCells.end(), LargerRenderCost);
5448        }
5449
5450        //////////
5451        //-- export some view cells for visualization
5452
5453        ViewCell::NewMail();
5454        const int limit = min(maxViewCells, (int)mViewCells.size());
5455       
5456        for (int i = 0; i < limit; ++ i)
5457        {
5458                cout << "creating output for view cell " << i << " ... ";
5459
5460                ViewCell *vc = sortViewCells ? // largest view cell pvs first?
5461                        mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 0.5f)] : mViewCells[i];
5462
5463                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
5464                        continue;
5465
5466                vc->Mail();
5467
5468                ObjectPvs pvs;
5469                mViewCellsTree->GetPvs(vc, pvs);
5470
5471                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
5472                Exporter *exporter = Exporter::GetExporter(s);
5473               
5474                const float pvsCost = mViewCellsTree->GetTrianglesInPvs(vc);
5475                cout << "view cell " << vc->GetId() << ": pvs cost=" << pvsCost << endl;
5476
5477                if (exportRays)
5478                {
5479                        ////////////
5480                        //-- export rays piercing this view cell
5481
5482                        // take rays stored with the view cells during subdivision
5483                        VssRayContainer vcRays;
5484            VssRayContainer collectRays;
5485
5486                        // collect initial view cells
5487                        ViewCellContainer leaves;
5488                        mViewCellsTree->CollectLeaves(vc, leaves);
5489
5490                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5491                for (vit = leaves.begin(); vit != vit_end; ++ vit)
5492                        {       
5493                                BspLeaf *vcLeaf = static_cast<BspViewCell *>(*vit)->mLeaves[0];
5494                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5495
5496                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5497                                {
5498                                        collectRays.push_back(*rit);
5499                                }
5500                        }
5501
5502                        const int raysOut = min((int)collectRays.size(), maxRays);
5503               
5504                        // prepare some rays for visualization
5505                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5506                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5507                        {
5508                                const float p = RandomValue(0.0f, (float)collectRays.size());
5509                       
5510                                if (p < raysOut)
5511                                {
5512                                        vcRays.push_back(*rit);
5513                                }
5514                        }
5515
5516                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5517                }
5518               
5519                ////////////////
5520                //-- export view cell geometry
5521
5522                exporter->SetWireframe();
5523
5524                Material m;//= RandomMaterial();
5525                m.mDiffuseColor = RgbColor(0, 1, 0);
5526                exporter->SetForcedMaterial(m);
5527
5528                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5529                exporter->SetFilled();
5530
5531                if (exportPvs)
5532                {
5533                        Intersectable::NewMail();
5534                        ObjectPvsIterator pit = pvs.GetIterator();
5535
5536                        cout << endl;
5537
5538                        // output PVS of view cell
5539                        while (pit.HasMoreEntries())
5540                        {
5541                                Intersectable *intersect = pit.Next();         
5542                               
5543                                if (!intersect->Mailed())
5544                                {
5545                                        intersect->Mail();
5546
5547                                        m = RandomMaterial();
5548                                        exporter->SetForcedMaterial(m);
5549                                        exporter->ExportIntersectable(intersect);
5550                                }
5551                        }
5552                        cout << endl;
5553                }
5554               
5555                DEL_PTR(exporter);
5556                cout << "finished" << endl;
5557        }
5558}
5559
5560
5561void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
5562{
5563        Exporter *exporter = Exporter::GetExporter("filter.x3d");
5564
5565        Vector3 bsize = mViewSpaceBox.Size();
5566        const Vector3 viewPoint(mViewSpaceBox.Center());
5567        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
5568        const Vector3 width = Vector3(w);
5569       
5570        PrVs testPrVs;
5571       
5572        if (exporter)
5573        {
5574                ViewCellContainer viewCells;
5575       
5576        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
5577
5578                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
5579
5580                exporter->SetWireframe();
5581
5582                exporter->SetForcedMaterial(RgbColor(1,1,1));
5583                exporter->ExportBox(tbox);
5584               
5585                exporter->SetFilled();
5586
5587                exporter->SetForcedMaterial(RgbColor(0,1,0));
5588                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
5589
5590                //exporter->ResetForcedMaterial();
5591                exporter->SetForcedMaterial(RgbColor(0,0,1));
5592                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
5593
5594        exporter->SetForcedMaterial(RgbColor(1,0,0));
5595                exporter->ExportGeometry(objects);
5596
5597                delete exporter;
5598        }
5599}
5600
5601
5602int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5603                                                                                                        ViewCellContainer &viewCells) const
5604{
5605        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
5606}
5607
5608
5609int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
5610                                                                                        const Vector3 &termination,
5611                                                                                        ViewCellContainer &viewcells)
5612{
5613        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
5614}
5615
5616
5617bool VspBspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
5618                                                                                                   const Vector3 &termination,
5619                                                                                                   ViewCell *viewCell)
5620{
5621        return false;
5622}
5623
5624
5625void VspBspViewCellsManager::VisualizeWithFromPointQueries()
5626{
5627        int numSamples;
5628       
5629        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
5630        cout << "samples" << numSamples << endl;
5631
5632        vector<RenderCostSample> samples;
5633 
5634        if (!mPreprocessor->GetRenderer())
5635                return;
5636
5637        //start the view point queries
5638        long startTime = GetTime();
5639        cout << "starting sampling of render cost ... ";
5640       
5641        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
5642
5643        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
5644
5645
5646        // for each sample:
5647        //    find view cells associated with the samples
5648        //    store the sample pvs with the pvs associated with the view cell
5649        //
5650        // for each view cell:
5651        //    compute difference point sampled pvs - view cell pvs
5652        //    export geometry with color coded pvs difference
5653       
5654    std::map<ViewCell *, ObjectPvs> sampleMap;
5655
5656        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
5657
5658        for (rit = samples.begin(); rit != rit_end; ++ rit)
5659        {
5660                RenderCostSample sample = *rit;
5661       
5662                ViewCell *vc = GetViewCell(sample.mPosition);
5663
5664                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
5665
5666                if (it == sampleMap.end())
5667                {
5668                        sampleMap[vc] = sample.mPvs;
5669                }
5670                else
5671                {
5672                        (*it).second.MergeInPlace(sample.mPvs);
5673                }
5674        }
5675
5676        // visualize the view cells
5677        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
5678
5679        Material m;//= RandomMaterial();
5680
5681        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
5682        {
5683                ViewCell *vc = (*vit).first;
5684               
5685                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
5686                const int pvsPtSamples = (*vit).second.GetSize();
5687
5688        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
5689                m.mDiffuseColor.b = 1.0f;
5690                //exporter->SetForcedMaterial(m);
5691                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
5692
5693                /*      // counting the pvss
5694                for (rit = samples.begin(); rit != rit_end; ++ rit)
5695                {
5696                        RenderCostSample sample = *rit;
5697                        ViewCell *vc = GetViewCell(sample.mPosition);
5698
5699                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
5700                        Mesh *hMesh = CreateMeshFromBox(box);
5701
5702                        DEL_PTR(hMesh);
5703                }
5704                */
5705        }
5706}
5707
5708
5709void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5710                                                                                                        ViewCell *vc,
5711                                                                                                        const AxisAlignedBox3 *sceneBox,
5712                                                                                                        const AxisAlignedPlane *clipPlane
5713                                                                                                        ) const
5714{
5715        if (clipPlane)
5716        {
5717                const Plane3 plane = clipPlane->GetPlane();
5718
5719                ViewCellContainer leaves;
5720                mViewCellsTree->CollectLeaves(vc, leaves);
5721                ViewCellContainer::const_iterator it, it_end = leaves.end();
5722
5723                for (it = leaves.begin(); it != it_end; ++ it)
5724                {
5725                        BspNodeGeometry geom;
5726                        BspNodeGeometry front;
5727                        BspNodeGeometry back;
5728
5729                        mVspBspTree->ConstructGeometry(*it, geom);
5730
5731                        const float eps = 0.0001f;
5732                        const int cf = geom.Side(plane, eps);
5733
5734                        if (cf == -1)
5735                        {
5736                                exporter->ExportPolygons(geom.GetPolys());
5737                        }
5738                        else if (cf == 0)
5739                        {
5740                                geom.SplitGeometry(front,
5741                                                                   back,
5742                                                                   plane,
5743                                                                   mViewSpaceBox,
5744                                                                   eps);
5745
5746                                if (back.Valid())
5747                                {
5748                                        exporter->ExportPolygons(back.GetPolys());
5749                                }                       
5750                        }
5751                }
5752        }
5753        else
5754        {
5755                // export mesh if available
5756                // TODO: some bug here?
5757                if (1 && vc->GetMesh())
5758                {
5759                        exporter->ExportMesh(vc->GetMesh());
5760                }
5761                else
5762                {
5763                        BspNodeGeometry geom;
5764                        mVspBspTree->ConstructGeometry(vc, geom);
5765                        exporter->ExportPolygons(geom.GetPolys());
5766                }
5767        }
5768}
5769
5770
5771int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
5772{
5773        ViewCellContainer leaves;
5774        mViewCellsTree->CollectLeaves(vc, leaves);
5775
5776        int maxDist = 0;
5777       
5778        // compute max height difference
5779        for (int i = 0; i < (int)leaves.size(); ++ i)
5780        {
5781                for (int j = 0; j < (int)leaves.size(); ++ j)
5782                {
5783                        BspLeaf *leaf = static_cast<BspViewCell *>(leaves[i])->mLeaves[0];
5784
5785                        if (i != j)
5786                        {
5787                                BspLeaf *leaf2 =static_cast<BspViewCell *>(leaves[j])->mLeaves[0];
5788                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
5789                               
5790                                if (dist > maxDist)
5791                                        maxDist = dist;
5792                        }
5793                }
5794        }
5795
5796        return maxDist;
5797}
5798
5799
5800ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
5801{
5802        if (!ViewCellsConstructed())
5803                return NULL;
5804
5805        if (!mViewSpaceBox.IsInside(point))
5806          return NULL;
5807
5808        return mVspBspTree->GetViewCell(point, active);
5809}
5810
5811
5812void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
5813{
5814        BspNodeGeometry geom;
5815        mVspBspTree->ConstructGeometry(vc, geom);
5816       
5817        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5818       
5819        IncludeNodeGeomInMesh(geom, *mesh);
5820        mesh->ComputeBoundingBox();
5821
5822        vc->SetMesh(mesh);
5823}
5824
5825
5826int VspBspViewCellsManager::CastBeam(Beam &beam)
5827{
5828        return mVspBspTree->CastBeam(beam);
5829}
5830
5831
5832void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
5833                                                                          const bool createMesh)
5834{
5835        float area = 0;
5836        float volume = 0;
5837
5838        ViewCellContainer leaves;
5839        mViewCellsTree->CollectLeaves(viewCell, leaves);
5840
5841        ViewCellContainer::const_iterator it, it_end = leaves.end();
5842
5843    for (it = leaves.begin(); it != it_end; ++ it)
5844        {
5845                BspNodeGeometry geom;
5846                mVspBspTree->ConstructGeometry(*it, geom);
5847
5848                const float lVol = geom.GetVolume();
5849                const float lArea = geom.GetArea();
5850
5851                area += lArea;
5852                volume += lVol;
5853
5854                if (createMesh)
5855                        CreateMesh(*it);
5856        }
5857
5858        viewCell->SetVolume(volume);
5859        viewCell->SetArea(area);
5860}
5861
5862
5863void VspBspViewCellsManager::TestSubdivision()
5864{
5865        ViewCellContainer leaves;
5866        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
5867
5868        ViewCellContainer::const_iterator it, it_end = leaves.end();
5869
5870        const float vol = mViewSpaceBox.GetVolume();
5871        float subdivVol = 0;
5872        float newVol = 0;
5873
5874        for (it = leaves.begin(); it != it_end; ++ it)
5875        {
5876                BspNodeGeometry geom;
5877                mVspBspTree->ConstructGeometry(*it, geom);
5878
5879                const float lVol = geom.GetVolume();
5880               
5881                newVol += lVol;
5882                subdivVol += (*it)->GetVolume();
5883               
5884                float thres = 0.9f;
5885                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
5886                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
5887        }
5888       
5889        Debug << "exact volume: " << vol << endl;
5890        Debug << "subdivision volume: " << subdivVol << endl;
5891        Debug << "new volume: " << newVol << endl;
5892}
5893
5894
5895void VspBspViewCellsManager::PrepareLoadedViewCells()
5896{
5897        // TODO: do I still need this here?
5898        if (0) mVspBspTree->RepairViewCellsLeafLists();
5899}
5900
5901
5902
5903/************************************************************************/
5904/*                 VspOspViewCellsManager implementation                */
5905/************************************************************************/
5906
5907
5908VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree,
5909                                                                                           const string &hierarchyType)
5910: ViewCellsManager(vcTree)
5911{
5912        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5913        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5914
5915        Debug << "compressing objects: " << mCompressObjects << endl;
5916        cout << "compressing objects: " << mCompressObjects << endl;
5917
5918        mHierarchyManager = CreateHierarchyManager(hierarchyType);
5919
5920        mHierarchyManager->SetViewCellsManager(this);
5921        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5922}
5923
5924
5925VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
5926: ViewCellsManager(vcTree), mHierarchyManager(hm)
5927{
5928        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5929        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5930
5931        Debug << "compressing objects: " << mCompressObjects << endl;
5932        cout << "compressing objects: " << mCompressObjects << endl;
5933
5934        mHierarchyManager->SetViewCellsManager(this);
5935        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5936}
5937
5938
5939Intersectable *VspOspViewCellsManager::GetIntersectable(const VssRay &ray,
5940                                                                                                                const bool isTermination) const
5941{
5942        if (mUseKdPvs)
5943                return ViewCellsManager::GetIntersectable(ray, isTermination);
5944        else
5945                return mHierarchyManager->GetIntersectable(ray, isTermination);
5946}
5947
5948
5949HierarchyManager *VspOspViewCellsManager::CreateHierarchyManager(const string &hierarchyType)
5950{
5951        HierarchyManager *hierarchyManager;
5952
5953        if (strcmp(hierarchyType.c_str(), "osp") == 0)
5954        {
5955                Debug << "hierarchy manager: osp" << endl;
5956                hierarchyManager = new HierarchyManager(HierarchyManager::KD_BASED_OBJ_SUBDIV);
5957        }
5958        else if (strcmp(hierarchyType.c_str(), "bvh") == 0)
5959        {
5960                Debug << "hierarchy manager: bvh" << endl;
5961                hierarchyManager = new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
5962        }
5963        else // only view space partition
5964        {
5965                Debug << "hierarchy manager: obj" << endl;
5966                hierarchyManager = new HierarchyManager(HierarchyManager::NO_OBJ_SUBDIV);
5967        }
5968
5969        return hierarchyManager;
5970}
5971
5972
5973VspOspViewCellsManager::~VspOspViewCellsManager()
5974{
5975        DEL_PTR(mHierarchyManager);
5976}
5977
5978
5979float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
5980{
5981        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
5982}
5983
5984
5985void VspOspViewCellsManager::CollectViewCells()
5986{
5987        // view cells tree constructed
5988        if (!ViewCellsTreeConstructed())
5989        {
5990                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
5991        }
5992        else
5993        {       // we can use the view cells tree hierarchy to get the right set
5994                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
5995        }
5996}
5997
5998
5999bool VspOspViewCellsManager::ViewCellsConstructed() const
6000{
6001        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
6002}
6003
6004
6005ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
6006{
6007        return new VspViewCell(mesh);
6008}
6009
6010
6011int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
6012                                                                                                 const VssRayContainer &rays)
6013{
6014        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
6015
6016        // skip rest if view cells were already constructed
6017        if (ViewCellsConstructed())
6018                return 0;
6019
6020        int sampleContributions = 0;
6021        VssRayContainer sampleRays;
6022
6023        int limit = min (mInitialSamples, (int)rays.size());
6024
6025        VssRayContainer constructionRays;
6026        VssRayContainer savedRays;
6027
6028        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
6029                  << ", actual rays: " << (int)rays.size() << endl;
6030
6031        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
6032
6033        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
6034        Debug << "saved rays: " << (int)savedRays.size() << endl;
6035
6036        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
6037
6038#if TEST_EVALUATION
6039        VssRayContainer::const_iterator tit, tit_end = constructionRays.end();
6040        for (tit = constructionRays.begin(); tit != tit_end; ++ tit)
6041        {
6042                storedRays.push_back(new VssRay(*(*tit)));
6043        }
6044#endif
6045
6046        /////////////////////////
6047        //-- print satistics for subdivision and view cells
6048
6049        Debug << endl << endl << *mHierarchyManager << endl;
6050
6051        ResetViewCells();
6052        //Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
6053
6054        //////////////
6055        //-- recast rest of rays
6056       
6057        const long startTime = GetTime();
6058        cout << "Computing remaining ray contributions ... ";
6059
6060        if (SAMPLE_AFTER_SUBDIVISION)
6061                ComputeSampleContributions(savedRays, true, false);
6062
6063        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
6064                  << " secs" << endl;
6065
6066        if (0)
6067        {       
6068                // real meshes are constructed at this stage
6069                cout << "finalizing view cells ... ";
6070        FinalizeViewCells(true);
6071                cout << "finished" << endl;
6072        }
6073
6074        return sampleContributions;
6075}
6076
6077
6078int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
6079                                                                                const VssRayContainer &rays)
6080{
6081        if (!ViewCellsConstructed())
6082        {
6083                Debug << "post process error: no view cells constructed" << endl;
6084                return 0;
6085        }
6086
6087        // if view cells were already constructed before post processing step
6088        // (e.g., because they were loaded), we are finished
6089        if (mViewCellsFinished)
6090        {
6091                FinalizeViewCells(true);
6092                EvaluateViewCellsStats();
6093
6094                return 0;
6095        }
6096
6097        // check if new view cells turned invalid
6098        int minPvs, maxPvs;
6099
6100        if (0)
6101        {
6102                minPvs = mMinPvsSize;
6103                maxPvs = mMaxPvsSize;
6104        }
6105        else
6106        {
6107                // problem matt: why did I start here from zero?
6108                minPvs = 0;
6109                maxPvs = mMaxPvsSize;
6110        }
6111
6112        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
6113        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
6114       
6115        SetValidity(minPvs, maxPvs);
6116
6117       
6118        // area is not up to date, has to be recomputed
6119        mTotalAreaValid = false;
6120        VssRayContainer postProcessRays;
6121        GetRaySets(rays, mPostProcessSamples, postProcessRays);
6122
6123        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
6124
6125
6126        // compute tree by merging the nodes of the spatial hierarchy
6127        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
6128        mViewCellsTree->SetRoot(root);
6129
6130        //////////////////////////
6131        //-- update pvs up to the root of the hierarchy
6132
6133        ObjectPvs pvs;
6134        UpdatePvsForEvaluation(root, pvs);
6135
6136
6137        //////////////////////
6138        //-- render simulation after merge + refine
6139
6140        cout << "\nview cells partition render time before compress" << endl << endl;
6141        static_cast<RenderSimulator *>(mRenderer)->RenderScene();
6142        SimulationStatistics ss;
6143        static_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
6144        cout << ss << endl;
6145       
6146
6147        mHierarchyManager->CreateUniqueObjectIds();
6148
6149        ///////////
6150        //-- compression
6151
6152        if (0) CompressViewCells();
6153
6154        /////////////
6155        //-- some tasks still to do on the view cells:
6156        //-- Compute meshes from view cell geometry, evaluate volume and / or area
6157
6158        if (1) FinalizeViewCells(true);
6159
6160        return 0;
6161}
6162
6163
6164int VspOspViewCellsManager::GetType() const
6165{
6166        return VSP_OSP;
6167}
6168
6169
6170ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
6171{
6172        // terminate recursion
6173        if (root->IsLeaf())
6174        {
6175                VspLeaf *leaf = static_cast<VspLeaf *>(root);
6176                leaf->GetViewCell()->SetMergeCost(0.0f);
6177                return leaf->GetViewCell();
6178        }
6179       
6180        VspInterior *interior = static_cast<VspInterior *>(root);
6181        ViewCellInterior *viewCellInterior = new ViewCellInterior();
6182               
6183        // evaluate merge cost for priority traversal
6184        const float mergeCost = -(float)root->mTimeStamp;
6185        viewCellInterior->SetMergeCost(mergeCost);
6186
6187        float volume = 0;
6188       
6189        VspNode *front = interior->GetFront();
6190        VspNode *back = interior->GetBack();
6191
6192        ObjectPvs frontPvs, backPvs;
6193
6194        /////////
6195        //-- recursivly compute child hierarchies
6196
6197        ViewCell *backVc = ConstructSpatialMergeTree(back);
6198        ViewCell *frontVc = ConstructSpatialMergeTree(front);
6199
6200        viewCellInterior->SetupChildLink(backVc);
6201        viewCellInterior->SetupChildLink(frontVc);
6202
6203        volume += backVc->GetVolume();
6204        volume += frontVc->GetVolume();
6205
6206        viewCellInterior->SetVolume(volume);
6207
6208        return viewCellInterior;
6209}
6210
6211
6212bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
6213{
6214        if (!ViewCellsConstructed())
6215                return ViewCellsManager::GetViewPoint(viewPoint);
6216
6217        // TODO: set reasonable limit
6218        const int limit = 20;
6219
6220        for (int i = 0; i < limit; ++ i)
6221        {
6222                viewPoint = mViewSpaceBox.GetRandomPoint();
6223
6224                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
6225                {
6226                        return true;
6227                }
6228        }
6229
6230        Debug << "failed to find valid view point, taking " << viewPoint << endl;
6231        return false;
6232}
6233
6234
6235void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
6236                                                                                                        ViewCell *vc,
6237                                                                                                        const AxisAlignedBox3 *sceneBox,
6238                                                                                                        const AxisAlignedPlane *clipPlane
6239                                                                                                        ) const
6240{
6241        Plane3 plane;
6242        if (clipPlane)
6243        {
6244                // arbitrary plane definition
6245                plane = clipPlane->GetPlane();
6246        }
6247
6248        ViewCellContainer leaves;
6249        mViewCellsTree->CollectLeaves(vc, leaves);
6250
6251        ViewCellContainer::const_iterator it, it_end = leaves.end();
6252
6253        for (it = leaves.begin(); it != it_end; ++ it)
6254        {
6255                VspViewCell *vspVc = static_cast<VspViewCell *>(*it);
6256                VspLeaf *l = vspVc->mLeaves[0];
6257
6258                const AxisAlignedBox3 box =
6259                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
6260               
6261                if (sceneBox && !Overlap(*sceneBox, box))
6262                        continue;
6263
6264                if (clipPlane)
6265                {
6266                        if (box.Side(plane) == -1)
6267                        {
6268                                exporter->ExportBox(box);
6269                        }
6270                        else if (box.Side(plane) == 0)
6271                        {
6272                                // intersection
6273                                AxisAlignedBox3 fbox, bbox;
6274                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
6275                                exporter->ExportBox(bbox);
6276                        }
6277                }
6278                else
6279                {
6280                        exporter->ExportBox(box);
6281                }
6282        }
6283}
6284
6285
6286bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
6287{
6288  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
6289  // validy update in preprocessor for all managers)
6290  return ViewCellsManager::ViewPointValid(viewPoint);
6291
6292  //    return mViewSpaceBox.IsInside(viewPoint) &&
6293  //               mVspTree->ViewPointValid(viewPoint);
6294}
6295
6296
6297float VspOspViewCellsManager::UpdateObjectCosts()
6298{
6299        float maxRenderCost = 0;
6300
6301        cout << "updating object pvs cost ... ";
6302        const long startTime = GetTime();
6303
6304        ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
6305
6306        Intersectable::NewMail();
6307
6308        const float invViewSpaceVol = 1.0f / GetViewSpaceBox().GetVolume();
6309
6310        for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
6311        {
6312                ViewCell *vc = *vit;
6313
6314                ObjectPvsIterator pit = vc->GetPvs().GetIterator();
6315
6316                // output PVS of view cell
6317                while (pit.HasMoreEntries())
6318                {               
6319                        Intersectable *obj = pit.Next();
6320                               
6321                        BvhNode *node = static_cast<BvhNode *>(obj);
6322                       
6323                        // hack!!
6324                        if (!node->IsLeaf())
6325                        {
6326                                cout << "error, can only process leaves" << endl;
6327                                return 0;
6328                        }
6329       
6330                        if (!node->Mailed())
6331                        {
6332                                node->Mail();
6333                                node->mRenderCost = 0;
6334                        }
6335
6336                        const float rc = (float)((BvhLeaf *)node)->mObjects.size();
6337
6338                        node->mRenderCost += rc * vc->GetVolume() * invViewSpaceVol;
6339
6340                        if (node->mRenderCost > maxRenderCost)
6341                                maxRenderCost = node->mRenderCost;
6342                }
6343        }
6344
6345        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3f << " secs" << endl;
6346
6347        return maxRenderCost;
6348}
6349
6350
6351void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
6352                                                                           const VssRayContainer &sampleRays)
6353{
6354        if (!ViewCellsConstructed())
6355                return;
6356
6357        VssRayContainer visRays;
6358        GetRaySets(sampleRays, mVisualizationSamples, visRays);
6359
6360        ////////////
6361        //-- export final view cells
6362
6363        Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
6364
6365        Vector3 scale(0.9f, 0.9f, 0.9f);
6366        //Vector3 scale(1.0f, 1.0f, 1.0f);
6367
6368        if (exporter)
6369        {
6370                // clamp to a scene boudning box
6371                if (CLAMP_TO_BOX)
6372                        exporter->mClampToBox = true;   
6373               
6374                const long starttime = GetTime();
6375                cout << "exporting final view cells (after initial construction + post process) ... " << endl;
6376
6377                // matt: hack for clamping scene
6378                AxisAlignedBox3 bbox = mViewSpaceBox;
6379                bbox.Scale(scale);
6380
6381                if (1 && mExportRays)
6382                {       
6383                        exporter->ExportRays(visRays, RgbColor(0, 1, 0));
6384                }
6385
6386                // hack color code
6387                const int savedColorCode = mColorCode;
6388
6389                EvaluateViewCellsStats();
6390                const int colorCode = 0;
6391
6392                const float maxRenderCost = -1;//UpdateObjectCosts();
6393                const bool exportBounds = false;
6394
6395                //cout << "maxRenderCost: " << maxRenderCost << endl;
6396                if (1)
6397                mHierarchyManager->ExportObjectSpaceHierarchy(exporter,
6398                                                                                                          objects,
6399                                                                                                          CLAMP_TO_BOX ? &bbox : NULL,
6400                                                                                                          maxRenderCost,
6401                                                                                                          exportBounds);
6402               
6403                //ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
6404                ExportViewCellsForViz(exporter, NULL, colorCode, GetClipPlane());
6405               
6406                delete exporter;
6407
6408                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
6409        }
6410
6411        if (1)
6412        {
6413                exporter = Exporter::GetExporter("final_object_partition.wrl");
6414
6415                if (exporter)
6416                {
6417                        if (CLAMP_TO_BOX)
6418                        {       
6419                                exporter->mClampToBox = true;   
6420                        }
6421
6422                        const long starttime = GetTime();
6423                        cout << "exporting final objects (after initial construction + post process) ... ";
6424
6425                        // matt: hack for clamping scene
6426                        AxisAlignedBox3 bbox = mViewSpaceBox;
6427                        bbox.Scale(scale);
6428
6429                        // hack color code (show pvs size)
6430                        const int savedColorCode = mColorCode;
6431
6432                        EvaluateViewCellsStats();
6433                        mColorCode = 1; // 0 = random, 1 = export pvs
6434
6435                        // don't visualize render cost
6436                        const float maxRenderCost = -1;
6437                        //const bool exportBounds = true;
6438                        const bool exportBounds = false;
6439
6440                        mHierarchyManager->ExportObjectSpaceHierarchy(exporter,
6441                                                                      objects,
6442                                                                                                                  CLAMP_TO_BOX ? &bbox : NULL,
6443                                                                                                                  maxRenderCost,
6444                                                                                                                  exportBounds);
6445
6446
6447                        delete exporter;
6448
6449                        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
6450                        mColorCode = savedColorCode;
6451                }
6452        }
6453
6454        // export some view cells
6455        int leafOut;
6456        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
6457
6458        const bool sortViewCells = false;
6459        const bool exportPvs = true;
6460        const bool exportRays = true;
6461        const int raysOut = 100;
6462
6463        ExportSingleViewCells(objects,
6464                                                  leafOut,
6465                                                  sortViewCells,
6466                                                  exportPvs,
6467                                                  exportRays,
6468                                                  raysOut,
6469                                                  "");
6470}
6471
6472
6473void VspOspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
6474                                                                                                   const int maxViewCells,
6475                                                                                                   const bool sortViewCells,
6476                                                                                                   const bool exportPvs,
6477                                                                                                   const bool exportRays,
6478                                                                                                   const int maxRays,
6479                                                                                                   const string &prefix,
6480                                                                                                   VssRayContainer *visRays)
6481{
6482        if (sortViewCells)
6483        {
6484                // sort view cells to visualize the view cells with highest render cost
6485                sort(mViewCells.begin(), mViewCells.end(), LargerRenderCost);
6486        }
6487
6488        ViewCell::NewMail();
6489        const int limit = min(maxViewCells, (int)mViewCells.size());
6490       
6491        cout << "\nExporting " << limit << " single view cells: " << endl;
6492       
6493        for (int i = 0; i < limit; ++ i)
6494        {
6495                cout << "creating output for view cell " << i << " ... ";
6496               
6497                // largest view cell pvs first of random view cell
6498                ViewCell *vc = sortViewCells ?
6499                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
6500               
6501                if (vc->Mailed()) // view cell already processed
6502                        continue;
6503
6504                vc->Mail();
6505
6506                ObjectPvs pvs;
6507                mViewCellsTree->GetPvs(vc, pvs);
6508
6509                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
6510                Exporter *exporter = Exporter::GetExporter(s);
6511               
6512                cout << "view cell " << vc->GetId() << ": pvs cost=" << mViewCellsTree->GetTrianglesInPvs(vc) << endl;
6513
6514                if (exportPvs)
6515                {
6516                        Material m;
6517                        Intersectable::NewMail();
6518                       
6519                        ObjectPvsIterator pit = pvs.GetIterator();
6520
6521                        // output PVS of view cell
6522                        while (pit.HasMoreEntries())
6523                        {               
6524                                Intersectable *intersect = pit.Next();
6525                               
6526                                if (!intersect->Mailed())
6527                                {
6528                                        m = RandomMaterial();
6529                                        exporter->SetForcedMaterial(m);
6530
6531                                        exporter->ExportIntersectable(intersect);
6532                                        intersect->Mail();
6533                                }
6534                        }
6535                }
6536
6537                if (exportRays)
6538                {
6539                        ////////////
6540                        //-- export the sample rays
6541
6542                        // output rays stored with the view cells during subdivision
6543                        VssRayContainer vcRays;
6544                        VssRayContainer collectRays;
6545
6546                        // collect intial view cells
6547                        ViewCellContainer leaves;
6548                        mViewCellsTree->CollectLeaves(vc, leaves);
6549
6550                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
6551
6552                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
6553                        {
6554                                VspLeaf *vcLeaf = static_cast<VspViewCell *>(*vit)->mLeaves[0];
6555                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
6556
6557                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
6558                                {
6559                                        collectRays.push_back(*rit);
6560                                }
6561                        }
6562
6563                        const int raysOut = min((int)collectRays.size(), maxRays);
6564
6565                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
6566
6567                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
6568                        {
6569                                const float p = RandomValue(0.0f, (float)collectRays.size());
6570
6571                                if (p < raysOut)
6572                                        vcRays.push_back(*rit);
6573                        }
6574
6575                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
6576                }
6577               
6578       
6579                /////////////////
6580                //-- export view cell geometry
6581
6582                exporter->SetWireframe();
6583
6584                Material m;
6585                m.mDiffuseColor = RgbColor(0, 1, 0);
6586                exporter->SetForcedMaterial(m);
6587
6588                ExportViewCellGeometry(exporter, vc, NULL, NULL);
6589                exporter->SetFilled();
6590
6591                DEL_PTR(exporter);
6592                cout << "finished" << endl;
6593        }
6594
6595        cout << endl;
6596}
6597
6598
6599int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
6600                                                                                                        ViewCellContainer &viewCells) const
6601{
6602        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
6603}
6604
6605
6606int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
6607                                                                                        const Vector3 &termination,
6608                                                                                        ViewCellContainer &viewcells)
6609{
6610        return mHierarchyManager->CastLineSegment(origin, termination, viewcells);
6611}
6612
6613
6614bool VspOspViewCellsManager::LineSegmentIntersects(const Vector3 &origin,
6615                                                                                                   const Vector3 &termination,
6616                                                                                                   ViewCell *viewCell)
6617{
6618        return false;
6619}
6620
6621
6622bool VspOspViewCellsManager::ExportViewCells(const string filename,
6623                                                                                         const bool exportPvs,
6624                                                                                         const ObjectContainer &objects)
6625{
6626        // no view cells were computed
6627        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
6628                return false;
6629
6630        if (strstr(filename.c_str(), ".bn"))
6631        {
6632                return ExportViewCellsBinary(filename, exportPvs, objects);
6633        }
6634
6635        //cout << "exporting binary" << endl; string fname("test.vc"); return ExportViewCellsBinary(fname, exportPvs, objects);
6636
6637        const long starttime = GetTime();
6638        cout << "exporting view cells to xml ... ";
6639       
6640        OUT_STREAM stream(filename.c_str());
6641
6642        // we need unique ids for each view cell
6643        CreateUniqueViewCellIds();
6644
6645        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
6646        stream << "<VisibilitySolution>" << endl;
6647
6648        if (exportPvs)
6649        {
6650        ///////////////
6651                //-- export bounding boxes
6652                //-- we need the boxes to identify objects in the target engine
6653
6654                if (mUseKdPvs)
6655                {
6656                        stream << "<BoundingBoxes>" << endl;
6657
6658                        int id = 0;
6659                        vector<KdIntersectable *>::const_iterator kit, kit_end = mPreprocessor->mKdTree->mKdIntersectables.end();
6660                       
6661                        for (kit = mPreprocessor->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
6662                        {
6663                                Intersectable *obj = (*kit);
6664                                const AxisAlignedBox3 box = obj->GetBox();
6665
6666                                // set kd node id
6667                                obj->SetId(id);
6668
6669                                stream << "<BoundingBox" << " id=\"" << id << "\""
6670                                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
6671                                       << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
6672                        }
6673
6674                        stream << "</BoundingBoxes>" << endl;
6675                }
6676                else
6677                {
6678                        mHierarchyManager->ExportBoundingBoxes(stream, objects);
6679                }
6680        }
6681
6682
6683        //////////////////////////
6684        //-- export the view cells and the pvs
6685
6686        const int numViewCells = mCurrentViewCellsStats.viewCells;
6687
6688        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
6689        mViewCellsTree->Export(stream, exportPvs);
6690        stream << "</ViewCells>" << endl;
6691
6692
6693        /////////////////
6694        //-- export the view space hierarchy
6695       
6696        stream << "<ViewSpaceHierarchy type=\"vsp\""
6697                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
6698                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
6699
6700        mHierarchyManager->GetVspTree()->Export(stream);
6701        stream << "</ViewSpaceHierarchy>" << endl;
6702
6703        /////////////////
6704        //-- export the object space hierarchy
6705       
6706        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
6707       
6708        stream << "</VisibilitySolution>" << endl;
6709        stream.close();
6710       
6711        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
6712        return true;
6713}
6714
6715
6716bool VspOspViewCellsManager::ExportViewCellsBinary(const string filename,
6717                                                                                                   const bool exportPvs,
6718                                                                                                   const ObjectContainer &objects)
6719{
6720        // no view cells constructed yet
6721        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
6722                return false;
6723
6724        const long starttime = GetTime();
6725        cout << "exporting view cells to binary format ... ";
6726       
6727        OUT_STREAM stream(filename.c_str());
6728
6729        // we need unique ids for each view cell
6730        CreateUniqueViewCellIds();
6731
6732        int numBoxes = mPreprocessor->mKdTree->mKdIntersectables.size();
6733        stream.write(reinterpret_cast<char *>(&numBoxes), sizeof(int));
6734
6735
6736    ///////////////
6737        //-- export bounding boxes
6738
6739        // we use bounding box intersection to identify pvs objects in the target engine
6740        vector<KdIntersectable *>::const_iterator kit, kit_end = mPreprocessor->mKdTree->mKdIntersectables.end();
6741
6742        int id = 0;
6743
6744        for (kit = mPreprocessor->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
6745        {
6746                Intersectable *obj = (*kit);
6747                // set the kd node id to identify the kd node as a pvs entry
6748                obj->SetId(id);
6749
6750                const AxisAlignedBox3 &box = obj->GetBox();
6751                Vector3 bmin = box.Min();
6752                Vector3 bmax = box.Max();
6753
6754                stream.write(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
6755                stream.write(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
6756                stream.write(reinterpret_cast<char *>(&id), sizeof(int));
6757        }
6758
6759        cout << "written " << numBoxes << " kd nodes" << endl;
6760
6761        ///////////////
6762        //-- export the view cells and the pvs
6763
6764        int numViewCells = mViewCells.size();
6765        stream.write(reinterpret_cast<char *>(&numViewCells), sizeof(int));
6766
6767        Vector3 vmin = mViewSpaceBox.Min();
6768        Vector3 vmax = mViewSpaceBox.Max();
6769
6770        stream.write(reinterpret_cast<char *>(&vmin), sizeof(Vector3));
6771        stream.write(reinterpret_cast<char *>(&vmax), sizeof(Vector3));
6772
6773
6774        //////////
6775        //-- export binary view cells
6776
6777        mViewCellsTree->ExportBinary(stream);
6778
6779
6780        /////////
6781        //-- export the view space hierarchy
6782       
6783        mHierarchyManager->GetVspTree()->ExportBinary(stream);
6784       
6785
6786        ////////
6787        //-- export the object space hierarchy
6788
6789        //mHierarchyManager->ExportObjectSpaceHierarchyBinary();
6790   
6791        stream.close();
6792       
6793        //mHierarchyManager->GetVspTree()->TestOutput("output.txt");
6794
6795        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
6796        return true;
6797}
6798
6799
6800ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
6801                                                                                          const bool active) const
6802{
6803        if (!ViewCellsConstructed())
6804                return NULL;
6805
6806        if (!mViewSpaceBox.IsInside(point))
6807                return NULL;
6808
6809        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
6810}
6811
6812
6813void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
6814{
6815        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
6816       
6817        ViewCellContainer leaves;
6818        mViewCellsTree->CollectLeaves(vc, leaves);
6819
6820        ViewCellContainer::const_iterator it, it_end = leaves.end();
6821
6822    for (it = leaves.begin(); it != it_end; ++ it)
6823        {
6824                VspLeaf *leaf = static_cast<VspViewCell *>(*it)->mLeaves[0];
6825                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
6826        IncludeBoxInMesh(box, *mesh);
6827        }
6828
6829        mesh->ComputeBoundingBox();
6830
6831        vc->SetMesh(mesh);
6832}
6833
6834
6835int VspOspViewCellsManager::CastBeam(Beam &beam)
6836{
6837        // matt: TODO
6838        return 0;
6839}
6840
6841
6842void VspOspViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
6843{
6844        float area = 0;
6845        float volume = 0;
6846
6847        ViewCellContainer leaves;
6848        mViewCellsTree->CollectLeaves(viewCell, leaves);
6849
6850        ViewCellContainer::const_iterator it, it_end = leaves.end();
6851
6852    for (it = leaves.begin(); it != it_end; ++ it)
6853        {
6854                VspLeaf *leaf = static_cast<VspViewCell *>(*it)->mLeaves[0];
6855               
6856                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
6857
6858                const float lVol = box.GetVolume();
6859                const float lArea = box.SurfaceArea();
6860
6861                area += lArea;
6862                volume += lVol;
6863
6864        CreateMesh(*it);
6865        }
6866
6867        viewCell->SetVolume(volume);
6868        viewCell->SetArea(area);
6869}
6870
6871
6872void VspOspViewCellsManager::PrepareLoadedViewCells()
6873{
6874        // TODO
6875}
6876
6877
6878void VspOspViewCellsManager::PrintCompressionStats(HierarchyManager *hm, const int pvsEntries)
6879{
6880        const float mem = (float)pvsEntries * ObjectPvs::GetEntrySize();
6881               
6882        float fullmem = mem +
6883                        (hm->GetVspTree()->GetStatistics().Leaves() * 16 +
6884                         hm->mBvHierarchy->GetStatistics().Leaves() * 16) / float(1024 * 1024);
6885
6886        cout << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
6887        Debug << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
6888}
6889
6890
6891void VspOspViewCellsManager::CompressViewCells()
6892{
6893        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
6894                return;
6895
6896
6897        ////////////
6898        //-- compression
6899
6900        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
6901
6902        cout << "before compression: " << endl;
6903        Debug << "before compression: " << endl;
6904       
6905        PrintCompressionStats(mHierarchyManager, pvsEntries);
6906
6907        if (mCompressObjects)
6908        {
6909                cout << "compressing in the objects: " << endl;
6910                Debug << "compressing in the objects: " << endl;
6911
6912                pvsEntries = mHierarchyManager->CompressObjectSpace();
6913        }
6914        else
6915        {
6916                cout << "compressing in the view space: " << endl;
6917                Debug << "compressing in the view space: " << endl;
6918
6919                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
6920                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
6921        }
6922
6923        PrintCompressionStats(mHierarchyManager, pvsEntries);
6924}
6925
6926
6927void VspOspViewCellsManager::CollectObjects(const AxisAlignedBox3 &box,
6928                                                                                        ObjectContainer &objects)
6929{
6930        mHierarchyManager->CollectObjects(box, objects);
6931}
6932
6933
6934void VspOspViewCellsManager::EvalViewCellPartition()
6935{
6936        int samplesPerPass;
6937        int castSamples = 0;
6938        int oldSamples = 0;
6939        int samplesForStats;
6940        char statsPrefix[100];
6941        char suffix[100];
6942        int splitsStepSize;
6943
6944        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
6945        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
6946        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", mEvaluationSamples);
6947        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
6948        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.stepSize", splitsStepSize);
6949       
6950        bool useHisto;
6951        int histoMem;
6952
6953        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
6954        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoMem", histoMem);
6955
6956        Debug << "step size: " << splitsStepSize << endl;
6957        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
6958        Debug << "view cell evaluation samples: " << mEvaluationSamples << endl;
6959        Debug << "view cell stats prefix: " << statsPrefix << endl;
6960
6961    cout << "reseting pvs ... ";
6962               
6963        // reset pvs and start over from zero
6964        mViewCellsTree->ResetPvs();
6965       
6966        cout << "finished" << endl;
6967    cout << "Evaluating view cell partition ... " << endl;
6968
6969        int pass = 0;
6970
6971        while (castSamples < mEvaluationSamples)
6972        {               
6973                ///////////////
6974                //-- we have to use uniform sampling strategy for construction rays
6975
6976                VssRayContainer evaluationSamples;
6977                const int samplingType = mEvaluationSamplingType;
6978
6979                long startTime = GetTime();
6980                Real timeDiff;
6981
6982                cout << "casting " << samplesPerPass << " samples ... ";
6983                Debug << "casting " << samplesPerPass << " samples ... ";
6984       
6985                // use mixed distributions
6986                CastEvaluationSamples(samplesPerPass, evaluationSamples);
6987
6988                timeDiff = TimeDiff(startTime, GetTime());
6989                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6990                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6991               
6992                // don't computed sample contributions
6993                // because already accounted for inside the mixture distribution!
6994               
6995                castSamples += samplesPerPass;
6996
6997                if ((castSamples >= samplesForStats + oldSamples) ||
6998                        (castSamples >= mEvaluationSamples))
6999                {
7000                        oldSamples += samplesForStats;
7001
7002                        ///////////
7003                        //-- output stats
7004
7005                        sprintf(suffix, "-%09d-eval.log", castSamples);
7006                        const string filename = string(statsPrefix) + string(suffix);
7007
7008                        startTime = GetTime();
7009                       
7010                        cout << "compute new statistics ... " << endl;
7011
7012                        ofstream ofstr(filename.c_str());
7013                        mHierarchyManager->EvaluateSubdivision(ofstr, splitsStepSize, false, useHisto, histoMem, pass);
7014
7015                        timeDiff = TimeDiff(startTime, GetTime());
7016                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
7017                        cout << "*************************************" << endl;
7018
7019                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
7020
7021                        ++ pass;
7022                }
7023
7024                disposeRays(evaluationSamples, NULL);
7025        }
7026
7027        ////////////
7028        //-- histogram
7029
7030        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
7031        int histoStepSize;
7032
7033        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
7034        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
7035
7036        if (useHisto)
7037        {
7038                // evaluate view cells in a histogram           
7039                char str[64];
7040
7041                // hack: just show final view cells
7042                const int pass = (int)mViewCells.size();
7043
7044                //for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
7045
7046                string filename;
7047
7048                cout << "computing histogram for " << pass << " view cells" << endl;
7049
7050                ///////////////////
7051                //-- evaluate histogram for pvs size
7052
7053                cout << "computing pvs histogram for " << pass << " view cells" << endl;
7054
7055                sprintf(str, "-%09d-histo-pvs2.log", pass);
7056                filename = string(statsPrefix) + string(str);
7057
7058                EvalViewCellHistogramForPvsSize(filename, pass);
7059        }
7060}
7061
7062
7063void VspOspViewCellsManager::FinalizeViewCells(const bool createMesh)
7064{       
7065        ViewCellsManager::FinalizeViewCells(createMesh);
7066
7067        if (mHierarchyManager->mUseTraversalTree)
7068        {       // create a traversal tree for optimal view cell casting
7069                mHierarchyManager->CreateTraversalTree();
7070        }
7071}
7072
7073
7074#if TEST_PACKETS
7075
7076float VspOspViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
7077                                                                                                                 const bool addContributions,
7078                                                                                                                 const bool storeViewCells,
7079                                                                                                                 const bool useHitObjects)
7080{
7081        if (!ViewCellsConstructed())
7082                return 0;
7083       
7084        float sum = 0.0f;
7085        VssRayContainer::const_iterator it, it_end = rays.end();
7086
7087        VssRayContainer tmpRays;       
7088
7089        for (it = rays.begin(); it != it_end; ++ it)
7090        {
7091                sum += ComputeSampleContribution(*(*it), addContributions, storeViewCells, useHitObjects);
7092
7093                tmpRays.push_back(new VssRay(*(*it)));
7094               
7095                if (tmpRays.size() == 4)
7096                {
7097                        // cast packets of 4 rays
7098                        RayPacket packet(tmpRays);
7099                        mHierarchyManager->CastLineSegment(packet);
7100               
7101                        for (int i = 0; i < 4; ++ i)
7102                        {
7103                                ComputeSampleContribution(*tmpRays[i], addContributions, true, useHitObjects);
7104                                // compare results
7105                                cout << "ray " << i << ": " << (int)tmpRays[i]->mViewCells.size() << " "
7106                                         << (int)packet.mViewCells[i].size() << endl;
7107                        }
7108                       
7109                        CLEAR_CONTAINER(tmpRays);
7110                }
7111        }
7112       
7113        CLEAR_CONTAINER(tmpRays);
7114
7115        cout << "view cell cast time: " << viewCellCastTimer.TotalTime() << " s" << endl;
7116        Debug << "view cell cast time: " << viewCellCastTimer.TotalTime() << " s" << endl;
7117
7118        cout << "pvs time: " << pvsTimer.TotalTime() << " s" << endl;
7119        Debug << "pvs time: " << pvsTimer.TotalTime() << " s" << endl;
7120       
7121        return sum;
7122}
7123
7124#endif
7125
7126
7127ViewCellsManager *ViewCellsManager::LoadViewCellsBinary(const string &filename,
7128                                                                                                                ObjectContainer &pvsObjects,
7129                                                                                                                bool finalizeViewCells,
7130                                                                                                                BoundingBoxConverter *bconverter)                                                                                               
7131{
7132        IN_STREAM stream(filename.c_str());
7133
7134        if (!stream.is_open())
7135        {
7136                Debug << "View cells loading failed: could not open file" << endl;
7137                return NULL;
7138        }
7139
7140        Debug << "loading boxes" << endl;
7141
7142        const long startTime = GetTime();
7143
7144        // load all the bounding boxes
7145        IndexedBoundingBoxContainer iboxes;
7146        ViewCellsManager::LoadIndexedBoundingBoxesBinary(stream, iboxes);
7147
7148        pvsObjects.reserve(iboxes.size());
7149
7150        if (bconverter)
7151        {
7152                // associate object ids with bounding boxes
7153                bconverter->IdentifyObjects(iboxes, pvsObjects);
7154        }
7155
7156
7157        ObjectContainer pvsLookup;
7158        pvsLookup.resize(iboxes.size());
7159
7160        for (size_t i = 0; i < pvsLookup.size(); ++ i)
7161        {
7162                pvsLookup[i] = NULL;
7163        }
7164
7165        for (size_t i = 0; i < pvsObjects.size(); ++ i)
7166        {
7167                pvsLookup[pvsObjects[i]->GetId()] = pvsObjects[i];
7168        }
7169
7170
7171        /////////////
7172        //-- load the view cells
7173       
7174        int numViewCells;
7175        stream.read(reinterpret_cast<char *>(&numViewCells), sizeof(int));
7176
7177        Debug << "loading " << numViewCells << " view cells " << endl;
7178
7179        Vector3 vmin, vmax;
7180
7181        stream.read(reinterpret_cast<char *>(&vmin), sizeof(Vector3));
7182        stream.read(reinterpret_cast<char *>(&vmax), sizeof(Vector3));
7183
7184        AxisAlignedBox3 viewSpaceBox(vmin, vmax);
7185
7186        Debug << "view space box: " << viewSpaceBox << endl;
7187
7188    ViewCellsTree *vcTree = new ViewCellsTree();
7189
7190        if (!vcTree->ImportBinary(stream, pvsLookup))
7191        {
7192                Debug << "Error: loading view cells tree failed!" << endl;
7193                delete vcTree;
7194       
7195                return NULL;
7196        }
7197
7198        Debug << "loading the view space partition tree" << endl;
7199        VspTree *vspTree = new VspTree(viewSpaceBox);
7200
7201        if (!vspTree->ImportBinary(stream))
7202        {
7203                Debug << "Error: loading vsp tree failed!" << endl;
7204                delete vcTree; delete vspTree;
7205
7206                return NULL;
7207        }
7208
7209
7210        HierarchyManager * hm =
7211                new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
7212
7213        hm->SetVspTree(vspTree);
7214
7215
7216        /////////
7217        //-- create view cells manager
7218       
7219        VspOspViewCellsManager *vm = new VspOspViewCellsManager(vcTree, hm);
7220
7221
7222        //////////////
7223        //-- do some more preparation
7224
7225        vm->mViewSpaceBox = viewSpaceBox;
7226        vm->mViewCells.clear();
7227
7228        ViewCellContainer viewCells;
7229        vcTree->CollectLeaves(vcTree->GetRoot(), viewCells);
7230
7231        ViewCellContainer::const_iterator cit, cit_end = viewCells.end();
7232
7233        for (cit = viewCells.begin(); cit != cit_end; ++ cit)
7234        {
7235                vm->mViewCells.push_back(*cit);
7236        }
7237
7238
7239        //////////////
7240        //-- associate view cells with vsp leaves
7241
7242        vector<VspLeaf *> vspLeaves;
7243        vspTree->CollectLeaves(vspLeaves);
7244
7245        vector<VspLeaf *>::const_iterator vit, vit_end = vspLeaves.end();
7246        cit = viewCells.begin();
7247
7248        for (vit = vspLeaves.begin(); vit != vit_end; ++ vit, ++ cit)
7249        {
7250                VspLeaf *leaf = *vit;
7251                VspViewCell *vc = static_cast<VspViewCell *>(*cit);
7252
7253                leaf->SetViewCell(vc);
7254                vc->mLeaves.push_back(leaf);
7255        }
7256
7257       
7258        /*for (cit = viewCells.begin(); cit != cit_end; ++ cit)
7259        {
7260                Debug << "pvssize: " << (*cit)->GetPvs().GetSize();
7261        }*/
7262
7263
7264        vm->mViewCellsFinished = true;
7265        vm->mMaxPvsSize = (int)pvsObjects.size();
7266
7267        if (finalizeViewCells)
7268        {
7269                // create the meshes and compute view cell volumes
7270                const bool createMeshes = true;
7271                vm->FinalizeViewCells(createMeshes);
7272        }
7273
7274        Debug << (int)vm->mViewCells.size() << " view cells loaded in "
7275                  << TimeDiff(startTime, GetTime()) * 1e-6f << " secs" << endl;
7276
7277        //vspTree->TestOutput("input.txt");
7278
7279        return vm;
7280}
7281
7282}
Note: See TracBrowser for help on using the repository browser.