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

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