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

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