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

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