source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp @ 3262

Revision 3262, 35.8 KB checked in by mattausch, 16 years ago (diff)

working on pompeii loading. fixed bug in obj conversion

Line 
1#include "Bvh.h"
2#include "Camera.h"
3#include "Plane3.h"
4#include "glInterface.h"
5#include "Triangle3.h"
6#include "SceneEntity.h"
7#include "Geometry.h"
8#include "RenderState.h"
9#include "Material.h"
10#include "gzstream.h"
11
12#include <queue>
13#include <stack>
14#include <fstream>
15#include <iostream>
16#include <iomanip>
17
18
19#ifdef _CRT_SET
20        #define _CRTDBG_MAP_ALLOC
21        #include <stdlib.h>
22        #include <crtdbg.h>
23
24        // redefine new operator
25        #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
26        #define new DEBUG_NEW
27#endif
28
29#define INVALID_TEST ((unsigned int)-1)
30
31using namespace std;
32
33
34namespace CHCDemoEngine
35{
36
37int BvhNode::sCurrentState = 0;
38
39
40/*
413 x---------x 2
42  |\         \
43  | \         \
44  |  \         \
45  |     4 x---------x 5
46  |   |         |
470 x   |     x 1 |
48   \  |         |
49    \ |         |
50     \|         |
51        7 x---------x 6             
52*/
53
54static unsigned int sIndices[] =       
55{7, // degenerated
56 7, 6, 4, 5, 3, 2, 0, 1,
57 1, 4, // degenerated
58 4, 3, 7, 0, 6, 1, 5, 2,
59 2 // degenerated
60};
61
62
63const static int NUM_INDICES_PER_BOX = 20;
64
65/*      Order of vertices
66        0 = (0, 0, 0)
67        1 = (1, 0, 0)
68        2 = (1, 1, 0)
69        3 = (0, 1, 0)
70        4 = (0, 1, 1)
71        5 = (1, 1, 1)
72        6 = (1, 0, 1)
73        7 = (0, 0, 1)
74*/
75
76static Plane3 sNearPlane;
77static float sNear;
78static Frustum sFrustum;
79
80/// these values are valid for all nodes
81static int sClipPlaneAABBVertexIndices[12];
82
83//#define ALIGN_INDICES
84
85
86BvhNode::BvhNode(BvhNode *parent):
87mParent(parent),
88mAxis(-1),
89mDepth(0),
90mFirst(-1),
91mLast(-1),
92mNumTestNodes(1),
93mTestNodesIdx(-1),
94mIndicesPtr(-1),
95mId(0),
96mIsMaxDepthForVirtualLeaf(false),
97mIsVirtualLeaf(false)
98{
99        for (int i = 0; i < NUM_STATES; ++ i)
100        {
101                mPlaneMask[i] = 0;
102                mPreferredPlane[i]= 0;
103                mLastRenderedFrame[i] = -1;
104        }
105}
106
107
108BvhNode::~BvhNode()
109{
110}
111
112
113void BvhNode::ResetVisibility()
114{
115        for (int i = 0; i < NUM_STATES; ++ i)
116        {
117                mVisibility[i].Reset();
118                mLastRenderedFrame[i] = -1;
119                mPlaneMask[i] = 0;
120                mPreferredPlane[i]= 0;
121        }
122}
123
124
125void BvhNode::VisibilityInfo::Reset()
126{
127        mIsVisible = false;
128        mAssumedVisibleFrameId = 0;
129        mLastVisitedFrame = -1;
130        mTimesInvisible = 0;
131        mIsFrustumCulled = false;
132        mIsNew = true;
133        mLastQueriedFrame = -1;
134}
135
136
137BvhInterior::~BvhInterior()
138{
139        DEL_PTR(mBack);
140        DEL_PTR(mFront);
141}
142
143
144BvhLeaf::~BvhLeaf()
145{
146}
147
148BvhInterior::BvhInterior(BvhNode *parent):
149mBack(NULL), mFront(NULL), BvhNode(parent)
150{}
151
152
153bool BvhInterior::IsLeaf() const
154{
155        return false;
156}
157
158
159
160BvhLeaf::BvhLeaf(BvhNode *parent): BvhNode(parent)
161{}
162
163
164bool BvhLeaf::IsLeaf() const
165{
166        return true;
167}
168
169
170
171/**********************************************************/
172/*                class Bvh implementation                */
173/**********************************************************/
174
175
176Bvh::Bvh()
177{
178        Init();
179}
180
181
182Bvh::Bvh(const SceneEntityContainer &staticEntities,
183                 const SceneEntityContainer &dynamicEntities)
184{
185        Init();
186
187        mGeometrySize = staticEntities.size() + dynamicEntities.size();
188        mGeometry = new SceneEntity*[mGeometrySize];
189
190        mStaticGeometrySize = staticEntities.size();
191        mDynamicGeometrySize = dynamicEntities.size();
192
193        for (size_t i = 0; i < mStaticGeometrySize; ++ i)
194        {
195                mGeometry[i] = staticEntities[i];
196        }
197
198        for (size_t i = 0; i < mDynamicGeometrySize; ++ i)
199        {
200                mGeometry[mStaticGeometrySize + i] = dynamicEntities[i];
201        }
202
203        cout << "max depth for testing children" << mMaxDepthForTestingChildren << endl;
204}
205
206
207Bvh::Bvh(const SceneEntityContainer &staticEntities,
208                 const SceneEntityContainer &dynamicEntities,
209                 int maxDepthForTestingChildren)
210{
211        Init();
212
213        mGeometrySize = staticEntities.size() + dynamicEntities.size();
214        mGeometry = new SceneEntity*[mGeometrySize];
215
216        mStaticGeometrySize = staticEntities.size();
217        mDynamicGeometrySize = dynamicEntities.size();
218
219        for (size_t i = 0; i < mStaticGeometrySize; ++ i)
220        {
221                mGeometry[i] = staticEntities[i];
222        }
223
224        for (size_t i = 0; i < mDynamicGeometrySize; ++ i)
225        {
226                mGeometry[mStaticGeometrySize + i] = dynamicEntities[i];
227        }
228
229        mMaxDepthForTestingChildren = maxDepthForTestingChildren;
230        cout << "max depth for testing children" << mMaxDepthForTestingChildren << endl;
231}
232
233
234Bvh::~Bvh()
235{
236        DEL_ARRAY_PTR(mVertices);
237        DEL_ARRAY_PTR(mIndices);
238        DEL_ARRAY_PTR(mTestIndices);
239        DEL_ARRAY_PTR(mGeometry);
240
241        if (mRoot) delete mRoot;
242        // delete vbo
243        glDeleteBuffersARB(1, &mVboId);
244}
245
246
247void Bvh::Init()
248{
249        mStaticRoot = NULL;
250        mDynamicRoot = NULL;
251        mRoot = NULL;
252
253        mVertices = NULL;
254        mIndices = NULL;
255        mTestIndices = NULL;
256        mCurrentIndicesPtr = 0;
257        mNumNodes = 0;
258       
259        // nodes are tested using the subnodes from 3 levels below
260        mMaxDepthForTestingChildren = 3;
261        // the ratio of area between node and subnodes where
262        // testing the subnodes as proxy is still considered feasable
263        mAreaRatioThreshold = 2.0f;
264        //mAreaRatioThreshold = 1.4f;
265
266        mVboId = -1;
267        // bound the maximal depth of the dynamic branch
268        mMaxDepthForDynamicBranch = 1;
269}
270
271
272
273//////////////////////
274//-- functions that are used during the main traversal
275
276void Bvh::PullUpLastVisited(BvhNode *node, int frameId) const
277{               
278        BvhNode *parent = node->GetParent();
279
280        while (parent && (parent->GetLastVisitedFrame() != frameId))
281        {
282                parent->SetLastVisitedFrame(frameId);
283                parent = parent->GetParent();
284        }
285}
286
287
288void Bvh::MakeParentsVisible(BvhNode *node)
289{
290        BvhNode *parent = node->GetParent();
291
292        while (parent && (!parent->IsVisible()))
293        {
294                parent->SetVisible(true);
295                parent = parent->GetParent();
296        }
297}
298
299
300////////////////////////////////
301
302void Bvh::CollectLeaves(BvhNode *node, BvhLeafContainer &leaves)
303{
304        stack<BvhNode *> tStack;
305        tStack.push(node);
306
307        while (!tStack.empty())
308        {
309                BvhNode *node = tStack.top();
310
311                tStack.pop();
312
313                if (!node->IsLeaf())
314                {
315                        BvhInterior *interior = static_cast<BvhInterior *>(node);
316
317                        tStack.push(interior->mFront);
318                        tStack.push(interior->mBack);
319                }
320                else
321                {
322                        leaves.push_back(static_cast<BvhLeaf *>(node));
323                }
324        }
325}
326
327
328int Bvh::CountNumNodes(BvhNode *node) const
329{
330        int numNodes = 0;
331
332        stack<BvhNode *> tStack;
333
334        tStack.push(node);
335
336        while (!tStack.empty())
337        {
338                BvhNode *node = tStack.top();
339                tStack.pop();
340
341                ++ numNodes;
342
343                if (!node->IsLeaf())
344                {
345                        BvhInterior *interior = static_cast<BvhInterior *>(node);
346
347                        tStack.push(interior->mFront);
348                        tStack.push(interior->mBack);
349                }
350        }
351
352        return numNodes;
353}
354
355
356void Bvh::CollectNodes(BvhNode *node, BvhNodeContainer &nodes)
357{
358        stack<BvhNode *> tStack;
359
360        tStack.push(node);
361
362        while (!tStack.empty())
363        {
364                BvhNode *node = tStack.top();
365                tStack.pop();
366
367                nodes.push_back(node);
368
369                if (!node->IsLeaf())
370                {
371                        BvhInterior *interior = static_cast<BvhInterior *>(node);
372
373                        tStack.push(interior->mFront);
374                        tStack.push(interior->mBack);
375                }
376        }
377}
378
379
380typedef pair<BvhNode *, int> tPair;
381
382void Bvh::CollectNodes(BvhNode *root, BvhNodeContainer &nodes, int depth)
383{
384        stack<tPair> tStack;
385        tStack.push(tPair(root, 0));
386
387        while (!tStack.empty())
388        {
389                BvhNode *node = tStack.top().first;
390                const int d = tStack.top().second;
391
392                tStack.pop();
393
394                // found node in specified depth => take this node
395                if ((d == depth) || (node->IsLeaf()))
396                {
397                        nodes.push_back(node);
398                }
399                else
400                {
401                        BvhInterior *interior = static_cast<BvhInterior *>(node);
402
403                        tStack.push(tPair(interior->mFront, d + 1));
404                        tStack.push(tPair(interior->mBack, d + 1));
405                }
406        }
407}
408
409
410SceneEntity **Bvh::GetGeometry(BvhNode *node, int &geometrySize) const
411{
412        geometrySize = node->CountPrimitives();
413        return mGeometry + node->mFirst;
414}
415
416
417bool Bvh::TestPlane(BvhNode *node, int i, bool &bIntersect)
418{
419        // do the test only if necessary
420        if (!(node->mPlaneMask[BvhNode::sCurrentState] & (1 << i)))
421        {
422                return true;
423        }
424
425
426        ////////
427        //-- test the n-vertex
428               
429        if ((node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 0], sFrustum.mClipPlanes[i]) > 0.0f))
430        {
431                // outside
432                node->mPreferredPlane[BvhNode::sCurrentState] = i;
433                return false;
434        }
435
436        ////////////
437        //-- test the p-vertex
438
439        if (node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 1], sFrustum.mClipPlanes[i]) <= 0.0f)
440        {
441                // completely inside: children don't need to check against this plane no more
442                node->mPlaneMask[BvhNode::sCurrentState] ^= 1 << i;
443        }
444        else
445        {
446                bIntersect = true;
447        }
448       
449        return true;
450}
451
452
453int     Bvh::IsWithinViewFrustum(BvhNode *node)
454{
455        bool bIntersect = false;
456
457        if (node->GetParent())
458                node->mPlaneMask[BvhNode::sCurrentState] = node->GetParent()->mPlaneMask[BvhNode::sCurrentState];
459
460        ////////
461        //-- apply frustum culling for the planes with index mPreferredPlane to 6
462
463        for (int i = node->mPreferredPlane[BvhNode::sCurrentState]; i < 6; ++ i)
464                if (!TestPlane(node, i, bIntersect)) return 0;
465       
466
467        //////////
468        //-- apply frustum culling for the planes with index 0 to mPreferredPlane
469
470        for (int i = 0; i < node->mPreferredPlane[BvhNode::sCurrentState]; ++ i)
471                if (!TestPlane(node, i, bIntersect)) return 0;
472       
473        return bIntersect ? -1 : 1;
474}
475
476
477static void CalcNPVertexIndices(const Frustum &frustum, int *indices)
478{
479        for (int i = 0; i < 6; ++ i)
480        {
481                // n-vertex
482                indices[i * 2 + 0] = AxisAlignedBox3::GetIndexNearestVertex(frustum.mClipPlanes[i].mNormal);
483                // p-vertex
484                indices[i * 2 + 1] = AxisAlignedBox3::GetIndexFarthestVertex(frustum.mClipPlanes[i].mNormal);   
485        }
486}
487
488
489void Bvh::InitFrame(Camera *cam, RenderState *state)
490{
491        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
492        mRoot->mPlaneMask[BvhNode::sCurrentState] = 0x3f;
493
494        cam->CalcFrustum(sFrustum);
495        CalcNPVertexIndices(sFrustum, sClipPlaneAABBVertexIndices);
496
497        // store near plane
498        sNearPlane = Plane3(cam->GetDirection(), cam->GetPosition());
499        sNear = cam->GetNear();
500
501        // update dynamic part of the hierarchy
502        //if (!mDynamicEntities.empty())
503        if (mDynamicGeometrySize)
504        {
505                UpdateDynamicBranch(mDynamicRoot);
506                UpdateDynamicBounds(state);
507        }
508}
509
510
511void Bvh::UpdateDistance(BvhNode *node) const
512{
513        // q: should we use distance to center rather than the distance to the near plane?
514        // distance to near plane can also be used for checking near plane intersection
515        //node->mDistance = sNearPlane.Distance(node->GetBox().Center());
516        node->mDistance = node->GetBox().GetMinDistance(sNearPlane);
517}
518
519
520float Bvh::CalcMaxDistance(BvhNode *node) const
521{
522#if 1
523        return node->GetBox().GetMaxDistance(sNearPlane);
524
525#else
526        // use bounding boxes of geometry to determine max dist
527        float maxDist = .0f;
528
529        int geometrySize;
530        SceneEntity **entities = GetGeometry(node, geometrySize);
531
532        for (int i = 0; i < geometrySize; ++ i)
533        {
534                SceneEntity *ent = entities[i];
535                float dist = ent->GetWorldBoundingBox().GetMaxDistance(sNearPlane);
536
537                if (dist > maxDist) maxDist = dist;
538        }
539
540        return maxDist;
541#endif
542}
543
544
545void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
546{
547        // hack: use dummy contayiner as wrapper in order to use multibox function
548        static BvhNodeContainer dummy(1);
549        dummy[0] = node;
550        RenderBounds(dummy, state, useTightBounds);
551}
552
553
554int Bvh::RenderBounds(const BvhNodeContainer &nodes,
555                                          RenderState *state,
556                                          bool useTightBounds)
557{
558        int renderedBoxes;
559
560        if (!useTightBounds)
561        {
562                // if not using tight bounds, rendering boxes in immediate mode
563                // is preferable to vertex arrays (less setup time)
564                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
565                       
566                for (nit = nodes.begin(); nit != nit_end; ++ nit)
567                {
568                        RenderBoundingBoxImmediate((*nit)->GetBox());
569                }
570
571                renderedBoxes = (int)nodes.size();
572        }
573        else
574        {
575                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
576                RenderBoundsWithDrawArrays(renderedBoxes, state);
577        }
578
579        return renderedBoxes;
580}
581
582
583int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
584{
585        ///////////////////
586        //-- for the first time we come here => create vbo and indices
587
588        if (!mIndices)
589        {       
590                // create list of indices
591                CreateIndices();
592        }
593
594        if (mVboId == -1)
595        {       
596                // prepare the vbo
597                PrepareVertices();
598        }
599
600        ///////////////
601
602        int numNodes = 0;
603
604        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
605
606        for (nit = nodes.begin(); nit != nit_end; ++ nit)
607        {
608                BvhNode *node = *nit;
609        const int numIndices = node->mNumTestNodes * NUM_INDICES_PER_BOX;
610               
611                // copy indices
612                memcpy(mIndices + numNodes * NUM_INDICES_PER_BOX,
613                           mTestIndices + node->mIndicesPtr,
614                           numIndices * sizeof(unsigned int));
615
616                numNodes += node->mNumTestNodes;
617        }
618
619        return numNodes;
620}
621
622
623void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
624{
625        /////////
626        //-- Render the vbo
627
628        if (state->GetCurrentVboId() != mVboId)
629        {
630                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
631                // set the vertex pointer to the vertex buffer
632                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
633
634                state->SetCurrentVboId(mVboId);
635        }
636
637        // we don't use the last or the first index (they are generate and only used to connect strips)
638        int numElements = numNodes * NUM_INDICES_PER_BOX - 1;
639        // don't render first degenerate index
640        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
641}
642
643
644void Bvh::CreateIndices()
645{
646        // collect bvh nodes
647        BvhNodeContainer nodes;
648        // first collect dynamic nodes so we make sure that they are in the beginning
649        CollectNodes(mDynamicRoot, nodes);
650        // then collect static nodes
651        CollectNodes(mStaticRoot, nodes);
652        //CollectNodes(mRoot, nodes);
653
654        cout << "creating new indices" << endl;
655
656        int numMaxIndices = 0;
657
658        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
659
660        for (lit = nodes.begin(); lit != lit_end; ++ lit)
661        {
662                int offset = (*lit)->mNumTestNodes * NUM_INDICES_PER_BOX;
663#ifdef ALIGN_INDICES
664                // align with 32 in order to speed up memcopy
665                offset = (offset / 32) * 32 + 32;
666#endif
667                numMaxIndices += offset;
668        }
669
670        cout << "creating global indices buffer" << endl;
671
672        if (mIndices)     delete [] mIndices;
673        if (mTestIndices) delete [] mTestIndices;
674
675        // global buffer: create it once so we don't have
676        // to allocate memory for each individual chunk of the node
677        mIndices = new unsigned int[numMaxIndices];
678        // create new index buffer for the individual nodes
679        mTestIndices = new unsigned int[numMaxIndices];
680       
681        mCurrentIndicesPtr = 0;
682
683        for (lit = nodes.begin(); lit != lit_end; ++ lit)
684        {
685                BvhNode *node = *lit;
686               
687                // resize array
688                node->mIndicesPtr = mCurrentIndicesPtr;
689                int numIndices = 0;
690
691                // the bounding boxes of the test nodes are rendered instead of the node itself
692                // => store their indices
693                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += NUM_INDICES_PER_BOX)
694                {
695                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
696
697                        // add vertex indices of boxes to root node
698                        for (int j = 0; j < NUM_INDICES_PER_BOX; ++ j)
699                        {
700                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
701                        }
702                }
703
704                // align with 32
705#ifdef ALIGN_INDICES
706                const int offset = (numIndices / 32) * 32 + 32;
707#else
708                const int offset = numIndices;
709#endif
710                mCurrentIndicesPtr += offset;
711        }
712}
713
714
715void Bvh::ComputeIds()
716{
717        // collect all nodes
718        BvhNodeContainer nodes;
719        //CollectNodes(mRoot, nodes);
720        // first collect dynamic nodes so we make sure that they are in the beginning
721        CollectNodes(mDynamicRoot, nodes);
722        // then collect static nodes
723        CollectNodes(mStaticRoot, nodes);
724        // also add root
725        nodes.push_back(mRoot);
726
727        // assign ids to all nodes of the hierarchy
728        int i = 0;
729        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
730
731        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
732        {
733                (*lit)->SetId(i);
734        }
735}
736
737
738void Bvh::PrepareVertices()
739{
740        // collect all nodes
741        BvhNodeContainer nodes;
742
743        nodes.reserve(GetNumNodes());
744        // first collect dynamic nodes so we make sure that they are in the beginning
745        CollectNodes(mDynamicRoot, nodes);
746        // then collect static nodes
747        CollectNodes(mStaticRoot, nodes);
748        // also add root
749        nodes.push_back(mRoot);
750
751        const unsigned int bufferSize = 8 * (int)nodes.size();
752        mVertices = new Vector3[bufferSize];
753       
754        int i = 0;
755       
756        // store bounding box vertices
757        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
758
759        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
760        {
761                BvhNode *node = *lit;
762
763                Vector3 v;
764
765                for (int j = 0; j < 8; ++ j)
766                {
767                        node->GetBox().GetVertex2(j, v);
768                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = v;
769                }
770        }
771
772        glGenBuffersARB(1, &mVboId);
773        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
774        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
775       
776        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
777                            bufferSize * sizeof(Vector3),
778                            mVertices,
779                                        //GL_STATIC_DRAW_ARB);
780                                        GL_DYNAMIC_DRAW_ARB);
781
782        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
783
784        // data handled by graphics driver from now on
785        DEL_ARRAY_PTR(mVertices);
786
787        cout << "******** created vbos for tighter bounds *********" << endl;
788}
789
790
791void Bvh::UpdateDynamicBounds(RenderState *state)
792{
793        // vbos not created yet
794        if (mVboId == -1) return;
795
796        // collect all nodes
797        static BvhNodeContainer nodes;
798        nodes.clear();
799
800        CollectNodes(mDynamicRoot, nodes);
801
802        const unsigned int bufferSize = 8 * (int)nodes.size();
803        if (!mVertices) mVertices = new Vector3[bufferSize];
804       
805        int i = 0;
806       
807        // store bounding box vertices
808        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
809
810        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
811        {
812                BvhNode *node = *lit;
813
814                for (int j = 0; j < 8; ++ j)
815                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
816        }
817       
818        if (state->GetCurrentVboId() != mVboId)
819        {
820                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
821                // set the vertex pointer to the vertex buffer
822                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
823                state->SetCurrentVboId(mVboId);
824        }
825
826        glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
827                                           bufferSize * sizeof(Vector3),
828                                           mVertices);
829}
830
831
832void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
833{
834        if (maxDepth != mMaxDepthForTestingChildren)
835        {
836                mMaxDepthForTestingChildren = maxDepth;
837                RecomputeBounds();
838        }
839}
840
841
842void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
843{
844        if (ratio != mAreaRatioThreshold)
845        {
846                mAreaRatioThreshold = ratio;
847                RecomputeBounds();
848        }
849}
850
851
852void Bvh::RecomputeBounds()
853{
854        // collect all nodes
855        BvhNodeContainer nodes;
856        CollectNodes(mRoot, nodes);
857
858        cout << "recomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
859
860        int success = 0;
861        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
862
863        for (lit = nodes.begin(); lit != lit_end; ++ lit)
864        {
865                BvhNode *node = *lit;
866
867                // recreate list of nodes that will be queried as a proxy
868                if (CreateNodeRenderList(node))
869                        ++ success;
870        }
871
872        float p = 100.0f * (float)success / nodes.size();
873        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
874
875        // recreate indices used for indirect mode rendering
876        if (mIndices) CreateIndices();
877}
878
879       
880bool Bvh::CreateNodeRenderList(BvhNode *node)
881{
882        BvhNodeContainer children;
883
884        // collect nodes that will be tested instead of the leaf node
885        // in order to get a tighter bounding box test
886        CollectNodes(node, children, mMaxDepthForTestingChildren);
887       
888
889        // using the tighter bounds is not feasable in case
890        // that the tighter bounds represent nearly the same projected area
891        // as the old bounding box. Test this property using either
892        // volume or area heuristics
893
894        float vol = 0;
895        float area = 0;
896
897        BvhNodeContainer::const_iterator cit;
898
899        for (cit = children.begin(); cit != children.end(); ++ cit)
900                area += (*cit)->GetBox().SurfaceArea();
901
902        const float areaRatio = area / node->GetBox().SurfaceArea();
903       
904        bool success;
905
906        if (areaRatio < mAreaRatioThreshold)
907                success = true;
908        else
909        {
910                // hack: only store node itself
911                children.clear();
912                children.push_back(node);
913
914                success = false;
915        }
916
917        // the new test nodes are added at the end of the vector
918        node->mTestNodesIdx = (int)mTestNodes.size();
919
920        // use the collected nodes as proxy for the occlusion tests
921        for (cit = children.begin(); cit != children.end(); ++ cit)
922        {
923                BvhNode *child = *cit;
924                mTestNodes.push_back(child);
925        }
926
927        node->mNumTestNodes = (int)children.size();
928
929        return success;
930}
931
932
933void Bvh::ResetNodeClassifications()
934{
935        BvhNodeContainer nodes;
936
937        nodes.reserve(GetNumNodes());
938        CollectNodes(mRoot, nodes);
939
940        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
941
942        for (lit = nodes.begin(); lit != lit_end; ++ lit)
943        {
944                (*lit)->ResetVisibility();
945        }
946}
947
948
949void Bvh::ComputeBvhStats(BvhNode *root, BvhStats &bvhStats)
950{
951        bvhStats.Reset();
952        std::stack<BvhNode *> nodeStack;
953        nodeStack.push(root);
954
955        int numVirtualLeaves = 0;
956        int numGeometry = 0;
957
958        while (!nodeStack.empty())
959        {
960                BvhNode *node = nodeStack.top();
961                nodeStack.pop();
962
963                if (node->IsVirtualLeaf())
964                {
965                        ++ numVirtualLeaves;
966                        numGeometry += node->CountPrimitives();
967
968                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
969
970                        bvhStats.mTriangles += CountTriangles(leaf);
971                        bvhStats.mLeafSA += leaf->mBox.SurfaceArea();
972                        bvhStats.mLeafVol += leaf->mBox.GetVolume();
973                }
974                else
975                {
976                        bvhStats.mInteriorSA += node->mBox.SurfaceArea();
977                        bvhStats.mInteriorVol += node->mBox.GetVolume();
978
979                        BvhInterior *interior = static_cast<BvhInterior *>(node);
980                       
981                        nodeStack.push(interior->mBack);
982                        nodeStack.push(interior->mFront);
983                }
984        }
985
986        bvhStats.mGeometryRatio = (float)numGeometry / numVirtualLeaves;
987        bvhStats.mTriangleRatio = (float)bvhStats.mTriangles / numVirtualLeaves;
988        bvhStats.mLeaves = numVirtualLeaves;
989}
990
991
992void Bvh::PrintBvhStats(const BvhStats &bvhStats) const
993{
994        cout << "\n============ BVH statistics =============" << endl;
995        cout << "interiorNodesSA = " << bvhStats.mInteriorSA / mRoot->mBox.SurfaceArea() << endl;
996        cout << "leafNodesSA = " << bvhStats.mLeafSA / mRoot->mBox.SurfaceArea() << endl;
997        cout << "interiorNodesVolume = " << bvhStats.mInteriorVol / mRoot->mBox.GetVolume() << endl;
998        cout << "leafNodesVolume = " << bvhStats.mLeafVol / mRoot->mBox.GetVolume() << endl;
999
1000        cout << "geometry per leaf: " << bvhStats.mGeometryRatio << endl;
1001        cout << "triangles per leaf: " << bvhStats.mTriangleRatio << endl;
1002        cout << "===========================================" << endl << endl;
1003}
1004
1005
1006int Bvh::CountTriangles(BvhNode *node) const
1007{
1008        int numTriangles = 0;
1009
1010        for (int i = node->mFirst; i <= node->mLast; ++ i)
1011        {
1012                numTriangles += mGeometry[i]->CountNumTriangles(0);
1013        }
1014
1015        return numTriangles;
1016}
1017
1018
1019float Bvh::GetArea(BvhNode *node) const
1020{
1021        return node->mArea;
1022}
1023
1024
1025void Bvh::UpdateNumLeaves(BvhNode *node) const
1026{
1027        if (node->IsLeaf())
1028        {
1029                node->mNumLeaves = 1;
1030        }
1031        else
1032        {
1033                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1034                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1035
1036                UpdateNumLeaves(f);
1037                UpdateNumLeaves(b);
1038
1039                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
1040        }
1041}
1042
1043
1044void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
1045{
1046        stack<BvhNode *> tStack;
1047        tStack.push(node);
1048
1049        while (!tStack.empty())
1050        {
1051                BvhNode *node = tStack.top();
1052                tStack.pop();
1053
1054                if (node->mIsVirtualLeaf)
1055                {
1056                        leaves.push_back(node);
1057                }
1058                else if (!node->IsLeaf())
1059                {
1060                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1061
1062                        tStack.push(interior->mFront);
1063                        tStack.push(interior->mBack);
1064                }
1065        }
1066}
1067
1068
1069void Bvh::SetVirtualLeaves(int numTriangles)
1070{
1071        // first invalidate old virtual leaves
1072        BvhNodeContainer leaves;
1073        CollectVirtualLeaves(mRoot, leaves);
1074
1075        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
1076
1077        for (bit = leaves.begin(); bit != bit_end; ++ bit)
1078        {
1079                (*bit)->mIsVirtualLeaf = false;
1080        }
1081
1082        mNumVirtualNodes = 0;
1083        // assign new virtual leaves based on specified #triangles per leaf
1084        std::stack<BvhNode *> nodeStack;
1085        nodeStack.push(mRoot);
1086
1087        while (!nodeStack.empty())
1088        {
1089                BvhNode *node = nodeStack.top();
1090                nodeStack.pop();
1091
1092                ++ mNumVirtualNodes;
1093
1094                if (node->IsLeaf())
1095                {
1096                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
1097                        leaf->mIsVirtualLeaf = true;
1098                }
1099                else
1100                {
1101                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1102
1103                        BvhNode *f = interior->mFront;
1104                        BvhNode *b = interior->mBack;
1105
1106                        if (node->mIsMaxDepthForVirtualLeaf ||
1107                                (CountTriangles(node) <= numTriangles))
1108                        {
1109                                 node->mIsVirtualLeaf = true;
1110                        }
1111                        else
1112                        {
1113                                nodeStack.push(interior->mBack);
1114                                nodeStack.push(interior->mFront);
1115                        }
1116                }
1117        }
1118
1119        /// Reset the node states
1120        ResetNodeClassifications();
1121}
1122
1123
1124void Bvh::ComputeMaxDepthForVirtualLeaves()
1125{
1126        // We initialize the maximal depth for virtual leaves
1127        // of this bvh, i.e., the nodes that are used as
1128        // leaves of the hierarchy during traversal.
1129
1130        // Initially they are set either
1131        // a) to the real leaves of the hierarchy or
1132        // b) the point where the subdivision on object level ends
1133        // and the subsequent nodes are just used to provide tighter bounds
1134        // (see article for the notations)
1135
1136        std::stack<BvhNode *> nodeStack;
1137        nodeStack.push(mRoot);
1138
1139        while (!nodeStack.empty())
1140        {
1141                BvhNode *node = nodeStack.top();
1142                nodeStack.pop();
1143
1144                if (node->IsLeaf())
1145                {
1146                        node->mIsMaxDepthForVirtualLeaf = true;
1147                }
1148                else
1149                {
1150                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1151
1152                        BvhNode *f = interior->mFront;
1153                        BvhNode *b = interior->mBack;
1154
1155                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
1156                        {
1157                                // point reached where beyond there would be no further reduction
1158                                // as both subtrees contain the same objects => stop here
1159                                // The tree beyond the current node is used to describe
1160                                // tighter bounds on the geometry contained  in it
1161                                node->mIsMaxDepthForVirtualLeaf = true;
1162                        }
1163                        else
1164                        {
1165                                nodeStack.push(f);
1166                                nodeStack.push(b);
1167                        }
1168                }
1169        }
1170}
1171
1172
1173// this function must be called once after hierarchy creation
1174void Bvh::PostProcess()
1175{
1176        CreateRoot();
1177
1178        ComputeMaxDepthForVirtualLeaves();
1179        // set virtual leaves for specified number of triangles
1180        SetVirtualLeaves(INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES);
1181        /// for each node compute the number of leaves under this node
1182        UpdateNumLeaves(mRoot);
1183        // compute new ids
1184        ComputeIds();
1185        // specify bounds for occlusion tests
1186        RecomputeBounds();
1187
1188        mBox = mRoot->GetBox();
1189
1190        // compute and print stats for whole (static + dynamic) bvh
1191        ComputeBvhStats(mRoot, mBvhStats);
1192        PrintBvhStats(mBvhStats);
1193
1194        // also output dynamic stats
1195        if (mDynamicGeometrySize)
1196        {
1197                BvhStats bvhStats;
1198                ComputeBvhStats(mDynamicRoot, bvhStats);
1199
1200                cout << "\n=========== Dynamic BVH statistics: =========" << endl;
1201                cout << "leaves = " << bvhStats.mLeaves << endl;
1202                cout << "interiorNodesSA = " << bvhStats.mInteriorSA << endl;
1203                cout << "leafNodesSA = " << bvhStats.mLeafSA << endl;
1204                cout << "interiorNodesVolume = " << bvhStats.mInteriorVol  << endl;
1205                cout << "leafNodesVolume = " << bvhStats.mLeafVol << endl;
1206
1207                cout << "geometry per leaf: " << bvhStats.mGeometryRatio << endl;
1208                cout << "triangles per leaf: " << bvhStats.mTriangleRatio << endl;
1209                cout << "=============================================" << endl << endl;
1210        }
1211}
1212
1213
1214void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
1215{
1216        const Vector3 l = box.Min();
1217        const Vector3 u = box.Max();
1218
1219        ///////////
1220        //-- render AABB as triangle strips
1221
1222        glBegin(GL_TRIANGLE_STRIP);
1223
1224        // render first half of AABB
1225        glVertex3f(l.x, l.y, u.z);
1226        glVertex3f(u.x, l.y, u.z);
1227        glVertex3f(l.x, u.y, u.z);
1228        glVertex3f(u.x, u.y, u.z);
1229        glVertex3f(l.x, u.y, l.z);
1230        glVertex3f(u.x, u.y, l.z);
1231        glVertex3f(l.x, l.y, l.z);
1232        glVertex3f(u.x, l.y, l.z);
1233
1234        glPrimitiveRestartNV();
1235
1236        // render second half of AABB
1237        glVertex3f(l.x, u.y, u.z);
1238        glVertex3f(l.x, u.y, l.z);
1239        glVertex3f(l.x, l.y, u.z);
1240        glVertex3f(l.x, l.y, l.z);
1241        glVertex3f(u.x, l.y, u.z);
1242        glVertex3f(u.x, l.y, l.z);
1243        glVertex3f(u.x, u.y, u.z);
1244        glVertex3f(u.x, u.y, l.z);
1245
1246        glEnd();
1247}
1248
1249
1250static void RenderBoxForViz(const AxisAlignedBox3 &box)
1251{
1252        glBegin(GL_LINE_LOOP);
1253        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1254        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1255        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1256        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1257        glEnd();
1258
1259        glBegin(GL_LINE_LOOP);
1260        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1261        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1262        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1263        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1264        glEnd();
1265
1266        glBegin(GL_LINE_LOOP);
1267        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1268        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1269        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1270        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1271        glEnd();
1272
1273        glBegin(GL_LINE_LOOP);
1274        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1275        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1276        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1277        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1278        glEnd();
1279
1280        glBegin(GL_LINE_LOOP);
1281        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1282        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1283        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1284        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1285        glEnd();
1286
1287        glBegin(GL_LINE_LOOP);
1288        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1289        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1290        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1291        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1292
1293        glEnd();
1294}
1295
1296
1297static Technique GetVizTechnique()
1298{
1299        Technique tech;
1300        tech.Init();
1301
1302        //tech.SetLightingEnabled(false);
1303        //tech.SetDepthWriteEnabled(false);
1304
1305        tech.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1306        tech.SetDiffuse(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1307        tech.SetAmbient(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1308
1309        return tech;
1310}
1311
1312
1313void Bvh::RenderBoundsForViz(BvhNode *node,
1314                                                         RenderState *state,
1315                                                         bool useTightBounds)
1316{
1317        Technique *oldTech = state->GetState();
1318        // we set a simple material
1319        static Technique boxMat = GetVizTechnique();
1320        boxMat.Render(state);
1321
1322        if (!useTightBounds)
1323        {
1324#if 1
1325                RenderBoxForViz(node->GetBox());
1326#else
1327                glPolygonMode(GL_FRONT, GL_LINE);
1328                RenderBoundingBoxImmediate(node->GetBox());
1329                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1330#endif
1331        }
1332        else
1333        {
1334                for (int i = 0; i < node->mNumTestNodes; ++ i)
1335                {
1336                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1337                }
1338        }
1339
1340        if (oldTech) oldTech->Render(state);
1341}
1342
1343
1344
1345////////////////////////
1346//-- functions for construction of the dynamic hierarchy
1347
1348int Bvh::SortTriangles(BvhLeaf *leaf,
1349                                           int axis,
1350                                           float position
1351                                           )
1352{
1353        int i = leaf->mFirst;
1354        int j = leaf->mLast;
1355
1356    while (1)
1357        {
1358                while (mGeometry[i]->GetWorldCenter()[axis] < position) ++ i;
1359                //while ((j > 0) && (position < mGeometry[j]->GetWorldCenter()[axis])) -- j;
1360                while (position < mGeometry[j]->GetWorldCenter()[axis]) -- j;
1361
1362                // sorting finished
1363                if (i >= j) break;
1364
1365                // swap entities
1366                swap(mGeometry[i], mGeometry[j]);
1367                       
1368                ++ i;
1369                -- j;
1370        }
1371
1372        return j;
1373}
1374
1375
1376int Bvh::SortTrianglesSpatialMedian(BvhLeaf *leaf,
1377                                                                        int axis
1378                                                                        )
1379{
1380        // spatial median
1381        float m = leaf->mBox.Center()[axis];
1382        return SortTriangles(leaf, axis, m);
1383}
1384
1385
1386BvhNode *Bvh::SubdivideLeaf(BvhLeaf *leaf,
1387                                                        int parentAxis
1388                                                        )
1389{
1390        if (TerminationCriteriaMet(leaf))
1391        {
1392                //cout << "leaf constructed:" << leaf->mBox << " " << leaf->mFirst << " " << leaf->mLast << endl;
1393                return leaf;
1394        }
1395
1396        //const int axis = (parentAxis + 1) % 3;
1397        const int axis = leaf->mBox.MajorAxis();
1398
1399        const int scale = 20;
1400
1401        // position of the split in the partailly sorted array of triangles
1402        // corresponding to this leaf
1403        int split = -1;
1404        float pos = -1.0f;
1405       
1406        // Spatial median subdivision
1407        split = SortTrianglesSpatialMedian(leaf, axis);
1408        pos = leaf->mBox.Center()[axis];
1409       
1410        if (split == leaf->mLast)
1411        {
1412                // no split could be achieved => just halve number of objects
1413                split = (leaf->mLast - leaf->mFirst) / 2;
1414                cerr << "no reduction " << leaf->CountPrimitives() << " " << leaf->mFirst << " " << leaf->mLast << endl;
1415        }
1416
1417        // create two more nodes
1418        mNumNodes += 2;
1419        BvhInterior *parent = new BvhInterior(leaf->GetParent());
1420        parent->mFirst = leaf->mFirst;
1421        parent->mLast = leaf->mLast;
1422       
1423        parent->mAxis = axis;
1424        parent->mBox = leaf->mBox;
1425        parent->mDepth = leaf->mDepth;
1426
1427        BvhLeaf *front = new BvhLeaf(parent);
1428
1429        parent->mBack = leaf;
1430        parent->mFront = front;
1431               
1432        // now assign the triangles to the subnodes
1433        front->mFirst = split + 1;
1434        front->mLast = leaf->mLast;
1435        front->mDepth = leaf->mDepth + 1;
1436
1437        leaf->mLast = split;
1438        leaf->mDepth = front->mDepth;
1439        leaf->mParent = parent;
1440       
1441        front->mBox = SceneEntity::ComputeBoundingBox(mGeometry + front->mFirst, front->CountPrimitives());
1442        leaf->mBox = SceneEntity::ComputeBoundingBox(mGeometry + leaf->mFirst, leaf->CountPrimitives());
1443
1444        // recursively continue subdivision
1445        parent->mBack = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mBack), axis);
1446        parent->mFront = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mFront), axis);
1447       
1448        return parent;
1449}
1450
1451
1452bool Bvh::TerminationCriteriaMet(BvhLeaf *leaf) const
1453{
1454        const bool criteriaMet =
1455                (leaf->mDepth > mMaxDepthForDynamicBranch) ||
1456                (leaf->CountPrimitives() == 1);
1457
1458        return criteriaMet;
1459}
1460
1461
1462void Bvh::UpdateDynamicBranch(BvhNode *node)
1463{
1464        if (node->IsLeaf())
1465        {
1466                int numEntities;
1467                SceneEntity **entities = GetGeometry(node, numEntities);
1468
1469                node->mBox = SceneEntity::ComputeBoundingBox(entities, numEntities);
1470                //cout << "box: " << node->mBox << endl;
1471        }
1472        else
1473        {
1474                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1475                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1476
1477                UpdateDynamicBranch(f);
1478                UpdateDynamicBranch(b);
1479
1480                node->mBox = f->mBox;
1481                node->mBox.Include(b->mBox);
1482        }
1483}
1484
1485
1486void Bvh::CreateDynamicBranch()
1487{
1488        // the bvh has two main branches
1489        // a static branch (the old root), and a dynamic branch
1490        // we create a 'dynamic' leaf which basically is a container
1491        // for all dynamic objects underneath
1492
1493        // the bounding boxes of the dynamic tree must be updated
1494        // once each frame in order to be able to incorporate
1495        // the movements of the objects within
1496
1497        DEL_PTR(mDynamicRoot);
1498
1499        BvhLeaf *l = new BvhLeaf(mRoot);
1500        mDynamicRoot = l;
1501
1502        l->mBox = SceneEntity::ComputeBoundingBox(mGeometry + mStaticGeometrySize,
1503                                                      (int)mDynamicGeometrySize);
1504
1505        l->mFirst = (int)mStaticGeometrySize;
1506        l->mLast = (int)mGeometrySize - 1;
1507        l->mArea = l->mBox.SurfaceArea();
1508       
1509        cout << "creating dynamic bvh branch"  << endl;
1510
1511        if (mDynamicGeometrySize)
1512        {
1513                mDynamicRoot = SubdivideLeaf(l, 0);
1514        }
1515}
1516
1517
1518bool Bvh::IntersectsNearPlane(BvhNode *node) const
1519{
1520        // note: we have problems with large scale object penetrating the near plane
1521        // (e.g., objects in the distance which are always handled to be visible)
1522        // especially annoying is this problem when using the frustum
1523        // fitting on the visible objects for shadow mapping
1524        // but don't see how to solve this issue without using costly calculations
1525       
1526        // we stored the near plane distance => we can use it also here
1527        float distanceToNearPlane = node->GetDistance();
1528        //float distanceToNearPlane = node->GetBox().GetMinDistance(sNearPlane);
1529       
1530        return (distanceToNearPlane < sNear);
1531}
1532
1533
1534void Bvh::CreateRoot()
1535{
1536        // create new root
1537        mRoot = new BvhInterior(NULL);
1538
1539        // the separation is a purely logical one
1540        // the bounding boxes of the child nodes are
1541        // identical to those of the root node
1542
1543        mRoot->mBox = mStaticRoot->mBox;
1544        mRoot->mBox.Include(mDynamicRoot->mBox);
1545
1546        mRoot->mArea = mRoot->mBox.SurfaceArea();
1547
1548        mRoot->mFirst = 0;
1549        mRoot->mLast = (int)mGeometrySize - 1;
1550
1551        //cout<<"f: " << mRoot->mFirst<< " l: " <<mRoot->mLast << endl;
1552        // add static root on left subtree
1553        mRoot->mFront = mStaticRoot;
1554        mStaticRoot->mParent = mRoot;
1555
1556        // add dynamic root on left subtree
1557        mRoot->mBack = mDynamicRoot;
1558        mDynamicRoot->mParent = mRoot;
1559}
1560 
1561
1562}
Note: See TracBrowser for help on using the repository browser.