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

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