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

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

finally found bvh tighter bounds bug

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