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

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