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

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