Ignore:
Timestamp:
08/29/06 18:28:00 (18 years ago)
Author:
szydlowski
Message:

Implemented PVS support in kdtree scene manager - not complete, defunct
modified BoundingBoxConverter? to work with KdTreeSceneManager?

File:
1 edited

Legend:

Unmodified
Added
Removed
  • GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTree.cpp

    r1285 r1296  
    2424namespace Ogre 
    2525{ 
    26         Real PlaneEvent::KT = 2.0; 
    27         Real PlaneEvent::KI = 1.0; 
    28  
    29         //---------------------------------------------------------------------------- 
    30         // determine if this event is left or right of the reference event 
    31         void PlaneEvent::classify(const PlaneEvent& e, PlaneEvent::Side side) 
    32         { 
    33                 // only classify events of the same dimension 
    34                 if (mDimension == e.mDimension) 
    35                 { 
    36                         if (mType == PET_END && mPosition[mDimension] <= e.mPosition[e.mDimension]) 
     26 
     27enum Intersection 
     28{ 
     29        OUTSIDE=0, 
     30        INSIDE=1, 
     31        INTERSECT=2 
     32}; 
     33 
     34Intersection intersect( const Ray &one, const AxisAlignedBox &two ) 
     35{ 
     36        // Null box? 
     37        if (two.isNull()) return OUTSIDE; 
     38 
     39        bool inside = true; 
     40        const Vector3* pCorners = two.getAllCorners(); 
     41        Vector3 origin = one.getOrigin(); 
     42        Vector3 dir = one.getDirection(); 
     43 
     44        Vector3 maxT(-1, -1, -1); 
     45 
     46        int i = 0; 
     47        for(i=0; i<3; i++ ) 
     48        { 
     49                if( origin[i] < pCorners[0][i] ) 
     50                { 
     51                        inside = false; 
     52                        if( dir[i] > 0 ) 
     53                        { 
     54                                maxT[i] = (pCorners[0][i] - origin[i])/ dir[i]; 
     55                        } 
     56                } 
     57                else if( origin[i] > pCorners[4][i] ) 
     58                { 
     59                        inside = false; 
     60                        if( dir[i] < 0 ) 
     61                        { 
     62                                maxT[i] = (pCorners[4][i] - origin[i]) / dir[i]; 
     63                        } 
     64                } 
     65        } 
     66 
     67        if( inside ) 
     68        { 
     69                return INTERSECT; 
     70        } 
     71        int whichPlane = 0; 
     72        if( maxT[1] > maxT[whichPlane]) 
     73                whichPlane = 1; 
     74        if( maxT[2] > maxT[whichPlane]) 
     75                whichPlane = 2; 
     76 
     77        if( ((int)maxT[whichPlane]) & 0x80000000 ) 
     78        { 
     79                return OUTSIDE; 
     80        } 
     81        for(i=0; i<3; i++ ) 
     82        { 
     83                if( i!= whichPlane ) 
     84                { 
     85                        float f = origin[i] + maxT[whichPlane] * dir[i]; 
     86                        if ( f < (pCorners[0][i] - 0.00001f) || 
     87                                f > (pCorners[4][i] +0.00001f ) ) 
     88                        { 
     89                                return OUTSIDE; 
     90                        } 
     91                } 
     92        } 
     93 
     94        return INTERSECT; 
     95 
     96} 
     97 
     98 
     99/** Checks how the second box intersects with the first. 
     100*/ 
     101Intersection intersect( const PlaneBoundedVolume &one, const AxisAlignedBox &two ) 
     102{ 
     103        // Null box? 
     104        if (two.isNull()) return OUTSIDE; 
     105 
     106        // Get corners of the box 
     107        const Vector3* pCorners = two.getAllCorners(); 
     108 
     109        // For each plane, see if all points are on the negative side 
     110        // If so, object is not visible. 
     111        // If one or more are, it's partial. 
     112        // If all aren't, full 
     113        int corners[ 8 ] = {0, 4, 3, 5, 2, 6, 1, 7}; 
     114        bool all_inside = true; 
     115        PlaneList::const_iterator i, iend; 
     116        iend = one.planes.end(); 
     117        for (i = one.planes.begin(); i != iend; ++i) 
     118        { 
     119                const Plane& plane = *i; 
     120                bool all_outside = true; 
     121 
     122                float distance = 0; 
     123 
     124                for ( int corner = 0; corner < 8; ++corner ) 
     125                { 
     126                        distance = plane.getDistance( pCorners[ corners[ corner ] ] ); 
     127                        all_outside = all_outside && ( distance < 0 ); 
     128                        all_inside = all_inside && ( distance >= 0 ); 
     129 
     130                        if ( !all_outside && !all_inside ) 
     131                                break; 
     132                } 
     133 
     134                if ( all_outside ) 
     135                        return OUTSIDE; 
     136        } 
     137 
     138        if ( all_inside ) 
     139                return INSIDE; 
     140        else 
     141                return INTERSECT; 
     142 
     143} 
     144 
     145 
     146/** Checks how the second box intersects with the first. 
     147*/ 
     148Intersection intersect( const AxisAlignedBox &one, const AxisAlignedBox &two ) 
     149{ 
     150        // Null box? 
     151        if (one.isNull() || two.isNull()) return OUTSIDE; 
     152 
     153        const Vector3 * outside = one.getAllCorners(); 
     154        const Vector3 *inside = two.getAllCorners(); 
     155 
     156        if ( inside[ 4 ].x < outside[ 0 ].x || 
     157                inside[ 4 ].y < outside[ 0 ].y || 
     158                inside[ 4 ].z < outside[ 0 ].z || 
     159                inside[ 0 ].x > outside[ 4 ].x || 
     160                inside[ 0 ].y > outside[ 4 ].y || 
     161                inside[ 0 ].z > outside[ 4 ].z ) 
     162        { 
     163                return OUTSIDE; 
     164        } 
     165 
     166        bool full = ( inside[ 0 ].x > outside[ 0 ].x && 
     167                inside[ 0 ].y > outside[ 0 ].y && 
     168                inside[ 0 ].z > outside[ 0 ].z && 
     169                inside[ 4 ].x < outside[ 4 ].x && 
     170                inside[ 4 ].y < outside[ 4 ].y && 
     171                inside[ 4 ].z < outside[ 4 ].z ); 
     172 
     173        if ( full ) 
     174                return INSIDE; 
     175        else 
     176                return INTERSECT; 
     177 
     178} 
     179 
     180/** Checks how the box intersects with the sphere. 
     181*/ 
     182Intersection intersect( const Sphere &one, const AxisAlignedBox &two ) 
     183{ 
     184        // Null box? 
     185        if (two.isNull()) return OUTSIDE; 
     186 
     187        float sradius = one.getRadius(); 
     188 
     189        sradius *= sradius; 
     190 
     191        Vector3 scenter = one.getCenter(); 
     192 
     193        const Vector3 *corners = two.getAllCorners(); 
     194 
     195        float s, d = 0; 
     196 
     197        Vector3 mndistance = ( corners[ 0 ] - scenter ); 
     198        Vector3 mxdistance = ( corners[ 4 ] - scenter ); 
     199 
     200        if ( mndistance.squaredLength() < sradius && 
     201                mxdistance.squaredLength() < sradius ) 
     202        { 
     203                return INSIDE; 
     204        } 
     205 
     206        //find the square of the distance 
     207        //from the sphere to the box 
     208        for ( int i = 0 ; i < 3 ; i++ ) 
     209        { 
     210                if ( scenter[ i ] < corners[ 0 ][ i ] ) 
     211                { 
     212                        s = scenter[ i ] - corners[ 0 ][ i ]; 
     213                        d += s * s; 
     214                } 
     215 
     216                else if ( scenter[ i ] > corners[ 4 ][ i ] ) 
     217                { 
     218                        s = scenter[ i ] - corners[ 4 ][ i ]; 
     219                        d += s * s; 
     220                } 
     221 
     222        } 
     223 
     224        bool partial = ( d <= sradius ); 
     225 
     226        if ( !partial ) 
     227        { 
     228                return OUTSIDE; 
     229        } 
     230 
     231        else 
     232        { 
     233                return INTERSECT; 
     234        } 
     235} 
     236 
     237Real PlaneEvent::KT = 2.0; 
     238Real PlaneEvent::KI = 1.0; 
     239 
     240//---------------------------------------------------------------------------- 
     241// determine if this event is left or right of the reference event 
     242void PlaneEvent::classify(const PlaneEvent& e, PlaneEvent::Side side) 
     243{ 
     244        // only classify events of the same dimension 
     245        if (mDimension == e.mDimension) 
     246        { 
     247                if (mType == PET_END && mPosition[mDimension] <= e.mPosition[e.mDimension]) 
     248                { 
     249                        mRenderable->setSide(PES_LEFT); 
     250                } 
     251                else if (mType == PET_START && mPosition[mDimension] >= e.mPosition[e.mDimension]) 
     252                { 
     253                        mRenderable->setSide(PES_RIGHT); 
     254                } 
     255                else if (mType == PET_ON) 
     256                { 
     257                        if (mPosition[mDimension] < e.mPosition[e.mDimension] || 
     258                                (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_LEFT)) 
    37259                        { 
    38260                                mRenderable->setSide(PES_LEFT); 
    39261                        } 
    40                         else if (mType == PET_START && mPosition[mDimension] >= e.mPosition[e.mDimension]) 
     262                        if (mPosition[mDimension] > e.mPosition[e.mDimension] || 
     263                                (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_RIGHT)) 
    41264                        { 
    42265                                mRenderable->setSide(PES_RIGHT); 
    43266                        } 
    44                         else if (mType == PET_ON) 
    45                         { 
    46                                 if (mPosition[mDimension] < e.mPosition[e.mDimension] || 
    47                                         (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_LEFT)) 
    48                                 { 
    49                                         mRenderable->setSide(PES_LEFT); 
    50                                 } 
    51                                 if (mPosition[mDimension] > e.mPosition[e.mDimension] || 
    52                                         (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_RIGHT)) 
    53                                 { 
    54                                         mRenderable->setSide(PES_RIGHT); 
    55                                 } 
    56                         } 
    57                 } 
    58         } 
    59  
    60         //---------------------------------------------------------------------------- 
    61         // clip this event to an aabb (move it so that the plane on one of the box planes) 
    62         PlaneEvent PlaneEvent::clip(AxisAlignedBox& box, PlaneEvent::Dimension dim) 
    63         { 
    64                 Vector3 newpos = mPosition, min = box.getMinimum(), max = box.getMaximum(); 
    65                 if (newpos[dim] < min[dim]) 
    66                         newpos[dim] = min[dim]; 
    67                 else if (newpos[dim] > max[dim]) 
    68                         newpos[dim] = max[dim]; 
    69  
    70                 return PlaneEvent(mRenderable, newpos, mDimension, mType); 
    71         } 
    72  
    73         //---------------------------------------------------------------------------- 
    74         // the surface area heuristic to determine the cost of splitting the parent aabb 
    75         // along the plane represented by this event 
    76         void PlaneEvent::SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split) 
    77         { 
    78                 Real mu = splitBox(parent, split.bleft, split.bright); 
    79                 Real sav = surfaceArea(parent); 
    80                 Real pl = surfaceArea(split.bleft) / sav; 
    81                 Real pr = surfaceArea(split.bright) / sav; 
    82                 Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu); 
    83                 Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu); 
    84  
    85                 if (costl < costr) 
    86                 { 
    87                         split.cost = costl; 
    88                         split.side = PES_LEFT; 
    89                         split.nleft = nLeft + nPlane; 
    90                         split.nright = nRight; 
    91                 } 
     267                } 
     268        } 
     269} 
     270 
     271//---------------------------------------------------------------------------- 
     272// clip this event to an aabb (move it so that the plane on one of the box planes) 
     273PlaneEvent PlaneEvent::clip(AxisAlignedBox& box, PlaneEvent::Dimension dim) 
     274{ 
     275        Vector3 newpos = mPosition, min = box.getMinimum(), max = box.getMaximum(); 
     276        if (newpos[dim] < min[dim]) 
     277                newpos[dim] = min[dim]; 
     278        else if (newpos[dim] > max[dim]) 
     279                newpos[dim] = max[dim]; 
     280 
     281        return PlaneEvent(mRenderable, newpos, mDimension, mType); 
     282} 
     283 
     284//---------------------------------------------------------------------------- 
     285// the surface area heuristic to determine the cost of splitting the parent aabb 
     286// along the plane represented by this event 
     287void PlaneEvent::SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split) 
     288{ 
     289        Real mu = splitBox(parent, split.bleft, split.bright); 
     290        Real sav = surfaceArea(parent); 
     291        Real pl = surfaceArea(split.bleft) / sav; 
     292        Real pr = surfaceArea(split.bright) / sav; 
     293        Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu); 
     294        Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu); 
     295 
     296        if (costl < costr) 
     297        { 
     298                split.cost = costl; 
     299                split.side = PES_LEFT; 
     300                split.nleft = nLeft + nPlane; 
     301                split.nright = nRight; 
     302        } 
     303        else 
     304        { 
     305                split.cost = costr; 
     306                split.side = PES_RIGHT; 
     307                split.nleft = nLeft; 
     308                split.nright = nPlane + nRight; 
     309 
     310        } 
     311        split.event = *this; 
     312} 
     313 
     314//---------------------------------------------------------------------------- 
     315// split the parent aabb with the plane in this event 
     316Real PlaneEvent::splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right) 
     317{ 
     318        Vector3 bmin = parent.getMinimum(); 
     319        Vector3 bmax = parent.getMaximum(); 
     320        // calculate the penalty for spliting the box that way 
     321        Real mu = lookupPenalty( 
     322                (mPosition[mDimension] - bmin[mDimension]) /  
     323                (bmax[mDimension] - bmin[mDimension])); 
     324        // set corners which are the same as parent AABB 
     325        left.setMinimum(bmin); 
     326        right.setMaximum(bmax); 
     327        // modify "inner" corners 
     328        bmin[mDimension] = mPosition[mDimension]; 
     329        bmax[mDimension] = mPosition[mDimension]; 
     330        // set the corners on the split plane 
     331        left.setMaximum(bmax); 
     332        right.setMinimum(bmin); 
     333 
     334        return mu; 
     335} 
     336 
     337//---------------------------------------------------------------------------- 
     338// compute surface area of a box ... DUH! 
     339Real PlaneEvent::surfaceArea(const AxisAlignedBox& box) 
     340{ 
     341        Vector3 sides = box.getMaximum() - box.getMinimum(); 
     342        return  2 * sides.x * sides.y + 
     343                2 * sides.y * sides.z + 
     344                2 * sides.z * sides.x; 
     345} 
     346 
     347//---------------------------------------------------------------------------- 
     348// lookup the penalty for placing the splitting plane near to the edge of the AABB 
     349// 0.0 <= p <= 1.0, p = 0.5 means the plane divides the aabb in half 
     350Real PlaneEvent::lookupPenalty(Real p) 
     351{ 
     352        // precomputed table of {x^6 + 1|0 <= x <= 1} 
     353        static Real mPenaltyLookupTable[PLT_SIZE]; 
     354        static bool init_done = false; 
     355 
     356        if (!init_done) 
     357        { 
     358                Real step = 1.0  / (PLT_SIZE - 1); 
     359                Real x = 0.0;  
     360                //LogManager::getSingleton().logMessage("### Calculating Lookup Table ###"); 
     361                for (int i = 0; i < PLT_SIZE; i++) 
     362                { 
     363                        mPenaltyLookupTable[i] = Math::Pow(x, 6) + 1.0; 
     364                        x += step; 
     365                        //LogManager::getSingleton().logMessage("### mPenaltyLookupTable[" + StringConverter::toString(i,3) + "]=" + StringConverter::toString(mPenaltyLookupTable[i])); 
     366                } 
     367                init_done = true; 
     368                //LogManager::getSingleton().logMessage("### Lookup Table Calculated ###"); 
     369        } 
     370 
     371        // normalize p to [0,1] 
     372        Real x = Math::Abs(p * 2 - 1); 
     373        // compute index 
     374        int i = Math::IFloor(x * (PLT_SIZE - 1)); 
     375 
     376        return mPenaltyLookupTable[i]; 
     377} 
     378 
     379//---------------------------------------------------------------------------- 
     380// compute cost of the split, reward splitting of empty space (lambda, const), 
     381// penalize splitting off 'thin' slices (mu, const) 
     382Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight) 
     383{ 
     384        // reward splitting off chunks of empty space 
     385        Real lambda = 1.0; 
     386        if (nLeft == 0 || nRight == 0) 
     387        { 
     388                lambda = 0.8; 
     389        } 
     390 
     391        // penalize splitting off small chunks (thin slices) 
     392        Real mu = 1.0; 
     393        if (pLeft < 0.1 || pRight < 0.1 || pLeft > 0.9 || pRight > 0.9) 
     394        { 
     395                mu = 1.5; 
     396        } 
     397        return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 
     398} 
     399 
     400//---------------------------------------------------------------------------- 
     401// compute cost of the split, reward splitting of empty space (lambda, const), 
     402// penalize splitting off 'thin' slices (mu, parameter) 
     403Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 
     404{ 
     405        // reward splitting off chunks of empty space 
     406        Real lambda = 1.0; 
     407        if (nLeft == 0 || nRight == 0) 
     408        { 
     409                lambda = 0.8; 
     410        } 
     411 
     412        return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 
     413} 
     414 
     415//---------------------------------------------------------------------------- 
     416// surface area heuristic modified for the priority queue method of building 
     417// the probabilities (p, pl, pr) are relative to the global (all enclosing) aabb 
     418void PlaneEvent::pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight,  
     419        AxisAlignedBox& parentBox, SplitInfo& split) 
     420{ 
     421        Real mu = splitBox(parentBox, split.bleft, split.bright); 
     422        Real p = parentSA / globalSA; 
     423        Real pl = surfaceArea(split.bleft) / globalSA; 
     424        Real pr = surfaceArea(split.bright) / globalSA; 
     425        Real costl = pqSplitCost(p, pl, pr, nLeft + nPlane, nRight, mu); 
     426        Real costr = pqSplitCost(p, pl, pr, nLeft, nPlane + nRight, mu); 
     427 
     428        if (costl < costr) 
     429        { 
     430                split.cost = costl; 
     431                split.side = PES_LEFT; 
     432                split.nleft = nLeft + nPlane; 
     433                split.nright = nRight; 
     434        } 
     435        else 
     436        { 
     437                split.cost = costr; 
     438                split.side = PES_RIGHT; 
     439                split.nleft = nLeft; 
     440                split.nright = nPlane + nRight; 
     441 
     442        } 
     443        split.event = *this; 
     444} 
     445 
     446//---------------------------------------------------------------------------- 
     447// compute split cost without any penalties 
     448Real PlaneEvent::pqSplitCost(Real pParent, Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 
     449{ 
     450        return pParent * KT + (KI * (pLeft * nLeft + pRight * nRight)); 
     451} 
     452 
     453//---------------------------------------------------------------------------- 
     454// DEBUG 
     455String PlaneEvent::print() 
     456{ 
     457        String dim, type; 
     458        if (mDimension == PED_X) 
     459                dim = "X"; 
     460        if (mDimension == PED_Y) 
     461                dim = "Y"; 
     462        if (mDimension == PED_Z) 
     463                dim = "Z"; 
     464        if (mType == PET_END) 
     465                type = "END  "; 
     466        if (mType == PET_ON) 
     467                type = "ON   "; 
     468        if (mType == PET_START) 
     469                type = "START"; 
     470        //return StringConverter::toString(mPosition[mDimension]) + " " + dim + " " + type; 
     471        return type + " " + dim + " " + StringConverter::toString(mPosition[mDimension]); 
     472}; 
     473 
     474//---------------------------------------------------------------------------- 
     475String SplitInfo::print() 
     476{ 
     477        String sside; 
     478        if (side == PlaneEvent::PES_BOTH) 
     479                sside = "BOTH "; 
     480        if (side == PlaneEvent::PES_LEFT) 
     481                sside = "LEFT "; 
     482        if (side == PlaneEvent::PES_RIGHT) 
     483                sside = "RIGHT"; 
     484        return "nLeft: " + StringConverter::toString(nleft, 4) + " nRight: " +  
     485                StringConverter::toString(nright, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 
     486                " Side: " + sside + " Event: " + event.print() + " Leftbox: " +  
     487                StringConverter::toString(bleft.getMinimum()) + ", " +  
     488                StringConverter::toString(bleft.getMaximum()) + " Rightbox: " + 
     489                StringConverter::toString(bright.getMinimum()) + ", " +  
     490                StringConverter::toString(bright.getMaximum()); 
     491}; 
     492 
     493//---------------------------------------------------------------------------- 
     494String KdTree::SplitCandidate::print() 
     495{                
     496        String sside; 
     497        if (side == PlaneEvent::PES_BOTH) 
     498                sside = "BOTH "; 
     499        if (side == PlaneEvent::PES_LEFT) 
     500                sside = "LEFT "; 
     501        if (side == PlaneEvent::PES_RIGHT) 
     502                sside = "RIGHT"; 
     503        return "List: " + StringConverter::toString(events->size(), 4) + " Objects: " + 
     504                StringConverter::toString(nObjects, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) +  
     505                " Decrease: " + StringConverter::toString(decrease, 8, 9) + " Side: " + sside + " Best: " + 
     506                best->print() +  " Box: " + StringConverter::toString(aabb.getMinimum()) + ", " 
     507                + StringConverter::toString(aabb.getMaximum()); 
     508 
     509}; 
     510 
     511//---------------------------------------------------------------------------- 
     512//---------------------------------------------------------------------------- 
     513//---------------------------------------------------------------------------- 
     514 
     515KdTree::KdTree(int maxdepth, BuildMethod bm):  
     516mMaxDepth(maxdepth),  
     517mBuildMethod(bm),  
     518mHiLiteLevel(0), 
     519mShowAllBoxes(false), 
     520mShowNodes(true), 
     521mKdRoot(0),  
     522mBuildLog(0) 
     523{ 
     524        init(); 
     525} 
     526 
     527KdTree::KdTree(int maxdepth, BuildMethod bm, int hilite, bool allboxes, bool shownodes): 
     528mMaxDepth(maxdepth),  
     529mBuildMethod(bm),  
     530mHiLiteLevel(hilite), 
     531mShowAllBoxes(allboxes), 
     532mShowNodes(shownodes), 
     533mKdRoot(0),  
     534mBuildLog(0) 
     535{ 
     536        init(); 
     537} 
     538 
     539KdTree::~KdTree() 
     540{ 
     541        delete mKdRoot; 
     542} 
     543 
     544void KdTree::init() 
     545{ 
     546        MaterialPtr mat; 
     547        TextureUnitState *tex; 
     548 
     549        // init visualization materials (unlit solid green/yellow) 
     550        mat = MaterialManager::getSingleton().getByName("KdTree/BoxHiLite"); 
     551        if (mat.isNull()) 
     552        { 
     553                ColourValue green(0, 1, 0); 
     554                mat = MaterialManager::getSingleton().create("KdTree/BoxHiLite", "General"); 
     555                //mat->setAmbient(green); 
     556                //mat->setDiffuse(green); 
     557                mat->setLightingEnabled(false); 
     558                tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 
     559                tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, green, green); 
     560        } 
     561 
     562        mat = MaterialManager::getSingleton().getByName("KdTree/BoxViz"); 
     563        if (mat.isNull()) 
     564        { 
     565                ColourValue yellow(1, 1, 0); 
     566                mat = MaterialManager::getSingleton().create("KdTree/BoxViz", "General"); 
     567                //mat->setAmbient(yellow); 
     568                //mat->setDiffuse(yellow); 
     569                mat->setLightingEnabled(false); 
     570                tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 
     571                tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, yellow, yellow); 
     572        } 
     573 
     574        // retrieve or create build log 
     575        try 
     576        { 
     577                mBuildLog = LogManager::getSingleton().getLog(KDTREE_LOGNAME); 
     578        } 
     579        catch (Exception&) 
     580        {                
     581                mBuildLog = LogManager::getSingleton().createLog(KDTREE_LOGNAME); 
     582        } 
     583 
     584        setEnhancedVis(false); 
     585} 
     586 
     587/************************************************************************/ 
     588/* KdTree insert/delete functions                                       */ 
     589/************************************************************************/ 
     590 
     591void KdTree::remove(KdRenderable * rend) 
     592{ 
     593        // DEBUG 
     594        //LogManager::getSingleton().logMessage("-- Removing SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName()); 
     595        std::queue<LeafPtr> cleanup; 
     596        LeafPtr leaf; 
     597        LeafSet ls = rend->getLeaves(); 
     598        LeafSet::iterator it = ls.begin(); 
     599        LeafSet::iterator end = ls.end(); 
     600        while (it != end) 
     601        { 
     602                cleanup.push(*it); 
     603                it++; 
     604        } 
     605        while (!cleanup.empty()) 
     606        { 
     607                leaf = cleanup.front(); 
     608                cleanup.pop(); 
     609                leaf->remove(rend); 
     610                bool gone = rend->detachFrom(leaf); 
     611                assert(gone && "Failed to detach leave which is abso-fuckin-lutely impossible!!!"); 
     612                //dump(); 
     613                recDelete(leaf); 
     614                //dump(); 
     615        } 
     616} 
     617 
     618void KdTree::recDelete(KdTree::Node * node) 
     619{ 
     620        if (node == 0) // DEBUG 
     621        { 
     622                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
     623                        "SNAFU while inserting KdRenderable into KdTree.", 
     624                        "KdTree::recInsert" ); 
     625                return; 
     626        } 
     627 
     628        if (node->isEmpty()) 
     629        { 
     630                if (node == mKdRoot) 
     631                { 
     632                        OGRE_DELETE(mKdRoot); 
     633                }  
    92634                else 
    93635                { 
    94                         split.cost = costr; 
    95                         split.side = PES_RIGHT; 
    96                         split.nleft = nLeft; 
    97                         split.nright = nPlane + nRight; 
    98  
    99                 } 
    100                 split.event = *this; 
    101         } 
    102  
    103         //---------------------------------------------------------------------------- 
    104         // split the parent aabb with the plane in this event 
    105         Real PlaneEvent::splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right) 
    106         { 
    107                 Vector3 bmin = parent.getMinimum(); 
    108                 Vector3 bmax = parent.getMaximum(); 
    109                 // calculate the penalty for spliting the box that way 
    110                 Real mu = lookupPenalty( 
    111                         (mPosition[mDimension] - bmin[mDimension]) /  
    112                         (bmax[mDimension] - bmin[mDimension])); 
    113                 // set corners which are the same as parent AABB 
    114                 left.setMinimum(bmin); 
    115                 right.setMaximum(bmax); 
    116                 // modify "inner" corners 
    117                 bmin[mDimension] = mPosition[mDimension]; 
    118                 bmax[mDimension] = mPosition[mDimension]; 
    119                 // set the corners on the split plane 
    120                 left.setMaximum(bmax); 
    121                 right.setMinimum(bmin); 
    122  
    123                 return mu; 
    124         } 
    125  
    126         //---------------------------------------------------------------------------- 
    127         // compute surface area of a box ... DUH! 
    128         Real PlaneEvent::surfaceArea(const AxisAlignedBox& box) 
    129         { 
    130                 Vector3 sides = box.getMaximum() - box.getMinimum(); 
    131                 return  2 * sides.x * sides.y + 
    132                         2 * sides.y * sides.z + 
    133                         2 * sides.z * sides.x; 
    134         } 
    135  
    136         //---------------------------------------------------------------------------- 
    137         // lookup the penalty for placing the splitting plane near to the edge of the AABB 
    138         // 0.0 <= p <= 1.0, p = 0.5 means the plane divides the aabb in half 
    139         Real PlaneEvent::lookupPenalty(Real p) 
    140         { 
    141                 // precomputed table of {x^6 + 1|0 <= x <= 1} 
    142                 static Real mPenaltyLookupTable[PLT_SIZE]; 
    143                 static bool init_done = false; 
    144  
    145                 if (!init_done) 
    146                 { 
    147                         Real step = 1.0  / (PLT_SIZE - 1); 
    148                         Real x = 0.0;  
    149                         //LogManager::getSingleton().logMessage("### Calculating Lookup Table ###"); 
    150                         for (int i = 0; i < PLT_SIZE; i++) 
    151                         { 
    152                                 mPenaltyLookupTable[i] = Math::Pow(x, 6) + 1.0; 
    153                                 x += step; 
    154                                 //LogManager::getSingleton().logMessage("### mPenaltyLookupTable[" + StringConverter::toString(i,3) + "]=" + StringConverter::toString(mPenaltyLookupTable[i])); 
    155                         } 
    156                         init_done = true; 
    157                         //LogManager::getSingleton().logMessage("### Lookup Table Calculated ###"); 
    158                 } 
    159  
    160                 // normalize p to [0,1] 
    161                 Real x = Math::Abs(p * 2 - 1); 
    162                 // compute index 
    163                 int i = Math::IFloor(x * (PLT_SIZE - 1)); 
    164  
    165                 return mPenaltyLookupTable[i]; 
    166         } 
    167  
    168         //---------------------------------------------------------------------------- 
    169         // compute cost of the split, reward splitting of empty space (lambda, const), 
    170         // penalize splitting off 'thin' slices (mu, const) 
    171         Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight) 
    172         { 
    173                 // reward splitting off chunks of empty space 
    174                 Real lambda = 1.0; 
    175                 if (nLeft == 0 || nRight == 0) 
    176                 { 
    177                         lambda = 0.8; 
    178                 } 
    179  
    180                 // penalize splitting off small chunks (thin slices) 
    181                 Real mu = 1.0; 
    182                 if (pLeft < 0.1 || pRight < 0.1 || pLeft > 0.9 || pRight > 0.9) 
    183                 { 
    184                         mu = 1.5; 
    185                 } 
    186                 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 
    187         } 
    188  
    189         //---------------------------------------------------------------------------- 
    190         // compute cost of the split, reward splitting of empty space (lambda, const), 
    191         // penalize splitting off 'thin' slices (mu, parameter) 
    192         Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 
    193         { 
    194                 // reward splitting off chunks of empty space 
    195                 Real lambda = 1.0; 
    196                 if (nLeft == 0 || nRight == 0) 
    197                 { 
    198                         lambda = 0.8; 
    199                 } 
    200  
    201                 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 
    202         } 
    203  
    204         //---------------------------------------------------------------------------- 
    205         // surface area heuristic modified for the priority queue method of building 
    206         // the probabilities (p, pl, pr) are relative to the global (all enclosing) aabb 
    207         void PlaneEvent::pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight,  
    208                 AxisAlignedBox& parentBox, SplitInfo& split) 
    209         { 
    210                 Real mu = splitBox(parentBox, split.bleft, split.bright); 
    211                 Real p = parentSA / globalSA; 
    212                 Real pl = surfaceArea(split.bleft) / globalSA; 
    213                 Real pr = surfaceArea(split.bright) / globalSA; 
    214                 Real costl = pqSplitCost(p, pl, pr, nLeft + nPlane, nRight, mu); 
    215                 Real costr = pqSplitCost(p, pl, pr, nLeft, nPlane + nRight, mu); 
    216  
    217                 if (costl < costr) 
    218                 { 
    219                         split.cost = costl; 
    220                         split.side = PES_LEFT; 
    221                         split.nleft = nLeft + nPlane; 
    222                         split.nright = nRight; 
     636                        KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 
     637                        if (node == parent->mLeft) 
     638                        { 
     639                                OGRE_DELETE(parent->mLeft); 
     640                        } 
     641                        else if (node == parent->mRight) 
     642                        { 
     643                                OGRE_DELETE(parent->mRight); 
     644                        } 
     645                        recDelete(parent); 
     646                } 
     647        } 
     648} 
     649 
     650void KdTree::insert(KdRenderable * rend) 
     651{ 
     652        // make sure the tree exists 
     653        if (mKdRoot) 
     654        { 
     655                // make sure the renderable is inside the world bounding box 
     656                AxisAlignedBox aabb = rend->getBoundingBox(); 
     657                AxisAlignedBox isect = mKdRoot->mAABB.intersection(aabb); 
     658                if (isect.getMinimum() == aabb.getMinimum() && isect.getMaximum() == aabb.getMaximum()) 
     659                { 
     660                        recInsert(mKdRoot, rend); 
    223661                } 
    224662                else 
    225663                { 
    226                         split.cost = costr; 
    227                         split.side = PES_RIGHT; 
    228                         split.nleft = nLeft; 
    229                         split.nright = nPlane + nRight; 
    230  
    231                 } 
    232                 split.event = *this; 
    233         } 
    234  
    235         //---------------------------------------------------------------------------- 
    236         // compute split cost without any penalties 
    237         Real PlaneEvent::pqSplitCost(Real pParent, Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 
    238         { 
    239                 return pParent * KT + (KI * (pLeft * nLeft + pRight * nRight)); 
    240         } 
    241  
    242         //---------------------------------------------------------------------------- 
    243         // DEBUG 
    244         String PlaneEvent::print() 
    245         { 
    246                 String dim, type; 
    247                 if (mDimension == PED_X) 
    248                         dim = "X"; 
    249                 if (mDimension == PED_Y) 
    250                         dim = "Y"; 
    251                 if (mDimension == PED_Z) 
    252                         dim = "Z"; 
    253                 if (mType == PET_END) 
    254                         type = "END  "; 
    255                 if (mType == PET_ON) 
    256                         type = "ON   "; 
    257                 if (mType == PET_START) 
    258                         type = "START"; 
    259                 //return StringConverter::toString(mPosition[mDimension]) + " " + dim + " " + type; 
    260                 return type + " " + dim + " " + StringConverter::toString(mPosition[mDimension]); 
    261         }; 
    262  
    263         //---------------------------------------------------------------------------- 
    264         String SplitInfo::print() 
    265         { 
    266                 String sside; 
    267                 if (side == PlaneEvent::PES_BOTH) 
    268                         sside = "BOTH "; 
    269                 if (side == PlaneEvent::PES_LEFT) 
    270                         sside = "LEFT "; 
    271                 if (side == PlaneEvent::PES_RIGHT) 
    272                         sside = "RIGHT"; 
    273                 return "nLeft: " + StringConverter::toString(nleft, 4) + " nRight: " +  
    274                         StringConverter::toString(nright, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 
    275                         " Side: " + sside + " Event: " + event.print() + " Leftbox: " +  
    276                         StringConverter::toString(bleft.getMinimum()) + ", " +  
    277                         StringConverter::toString(bleft.getMaximum()) + " Rightbox: " + 
    278                         StringConverter::toString(bright.getMinimum()) + ", " +  
    279                         StringConverter::toString(bright.getMaximum()); 
    280         }; 
    281  
    282         //---------------------------------------------------------------------------- 
    283         String KdTree::SplitCandidate::print() 
    284         {                
    285                 String sside; 
    286                 if (side == PlaneEvent::PES_BOTH) 
    287                         sside = "BOTH "; 
    288                 if (side == PlaneEvent::PES_LEFT) 
    289                         sside = "LEFT "; 
    290                 if (side == PlaneEvent::PES_RIGHT) 
    291                         sside = "RIGHT"; 
    292                 return "List: " + StringConverter::toString(events->size(), 4) + " Objects: " + 
    293                         StringConverter::toString(nObjects, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) +  
    294                         " Decrease: " + StringConverter::toString(decrease, 8, 9) + " Side: " + sside + " Best: " + 
    295                         best->print() +  " Box: " + StringConverter::toString(aabb.getMinimum()) + ", " 
    296                         + StringConverter::toString(aabb.getMaximum()); 
    297  
    298         }; 
    299  
    300         //---------------------------------------------------------------------------- 
    301         //---------------------------------------------------------------------------- 
    302         //---------------------------------------------------------------------------- 
    303  
    304         KdTree::KdTree(int maxdepth, BuildMethod bm):  
    305         mMaxDepth(maxdepth),  
    306         mBuildMethod(bm),  
    307         mHiLiteLevel(0), 
    308         mShowAllBoxes(false), 
    309         mShowNodes(true), 
    310         mKdRoot(0),  
    311         mBuildLog(0) 
    312         { 
    313                 init(); 
    314         } 
    315  
    316         KdTree::KdTree(int maxdepth, BuildMethod bm, int hilite, bool allboxes, bool shownodes): 
    317         mMaxDepth(maxdepth),  
    318         mBuildMethod(bm),  
    319         mHiLiteLevel(hilite), 
    320         mShowAllBoxes(allboxes), 
    321         mShowNodes(shownodes), 
    322         mKdRoot(0),  
    323         mBuildLog(0) 
    324         { 
    325                 init(); 
    326         } 
    327  
    328         KdTree::~KdTree() 
    329         { 
    330                 delete mKdRoot; 
    331         } 
    332  
    333         void KdTree::init() 
    334         { 
    335                 MaterialPtr mat; 
    336                 TextureUnitState *tex; 
    337  
    338                 // init visualization materials (unlit solid green/yellow) 
    339                 mat = MaterialManager::getSingleton().getByName("KdTree/BoxHiLite"); 
    340                 if (mat.isNull()) 
    341                 { 
    342                         ColourValue green(0, 1, 0); 
    343                         mat = MaterialManager::getSingleton().create("KdTree/BoxHiLite", "General"); 
    344                         //mat->setAmbient(green); 
    345                         //mat->setDiffuse(green); 
    346                         mat->setLightingEnabled(false); 
    347                         tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 
    348                         tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, green, green); 
    349                 } 
    350  
    351                 mat = MaterialManager::getSingleton().getByName("KdTree/BoxViz"); 
    352                 if (mat.isNull()) 
    353                 { 
    354                         ColourValue yellow(1, 1, 0); 
    355                         mat = MaterialManager::getSingleton().create("KdTree/BoxViz", "General"); 
    356                         //mat->setAmbient(yellow); 
    357                         //mat->setDiffuse(yellow); 
    358                         mat->setLightingEnabled(false); 
    359                         tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 
    360                         tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, yellow, yellow); 
    361                 } 
    362  
    363                 // retrieve or create build log 
    364                 try 
    365                 { 
    366                         mBuildLog = LogManager::getSingleton().getLog(KDTREE_LOGNAME); 
    367                 } 
    368                 catch (Exception&) 
    369                 {                
    370                         mBuildLog = LogManager::getSingleton().createLog(KDTREE_LOGNAME); 
    371                 } 
    372  
    373                 setEnhancedVis(false); 
    374         } 
    375  
    376         /************************************************************************/ 
    377         /* KdTree insert/delete functions                                       */ 
    378         /************************************************************************/ 
    379  
    380         void KdTree::remove(KdRenderable * rend) 
    381         { 
    382                 // DEBUG 
    383                 //LogManager::getSingleton().logMessage("-- Removing SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName()); 
    384                 std::queue<LeafPtr> cleanup; 
    385                 LeafPtr leaf; 
    386                 LeafSet ls = rend->getLeaves(); 
    387                 LeafSet::iterator it = ls.begin(); 
    388                 LeafSet::iterator end = ls.end(); 
    389                 while (it != end) 
    390                 { 
    391                         cleanup.push(*it); 
    392                         it++; 
    393                 } 
    394                 while (!cleanup.empty()) 
    395                 { 
    396                         leaf = cleanup.front(); 
    397                         cleanup.pop(); 
    398                         leaf->remove(rend); 
    399                         bool gone = rend->detachFrom(leaf); 
    400                         assert(gone && "Failed to detach leave which is abso-fuckin-lutely impossible!!!"); 
    401                         //dump(); 
    402                         recDelete(leaf); 
    403                         //dump(); 
    404                 } 
    405         } 
    406  
    407         void KdTree::recDelete(KdTree::Node * node) 
    408         { 
    409                 if (node == 0) // DEBUG 
     664                        //LogManager::getSingleton().logMessage("Inserted node outside of world AABB."); 
     665                        KdRenderableList nodelist; 
     666                        nodelist.push_back(rend); 
     667                        addRendToList(mKdRoot, nodelist); 
     668                        OGRE_DELETE(mKdRoot); 
     669                        mKdRoot = buildFromList(nodelist, 0, AxisAlignedBox()); 
     670                } 
     671        } 
     672        // otherwise build a new one 
     673        else 
     674        { 
     675                build(rend); 
     676        } 
     677} 
     678 
     679void KdTree::recInsert(KdTree::Node * node, KdRenderable * rend) 
     680{ 
     681        if (node == 0) // DEBUG 
     682        { 
     683                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
     684                        "SNAFU while inserting KdRenderable into KdTree.", 
     685                        "KdTree::recInsert" ); 
     686                return; 
     687        } 
     688 
     689        // rebuild the leaf/replace with subtree ... 
     690        if (node->isLeaf()) 
     691        { 
     692                //LogManager::getSingleton().logMessage("## Replacing leaf."); 
     693                rebuildSubtree(node, rend); 
     694        } 
     695        else 
     696        { 
     697                KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
     698                AxisAlignedBox aabb = rend->getBoundingBox(); 
     699                Plane::Side smin = branch->mSplitPlane->getSide(aabb.getMinimum()); 
     700                Plane::Side smax = branch->mSplitPlane->getSide(aabb.getMaximum()); 
     701                if (smin == smax) 
     702                { 
     703                        if (smax == Plane::NEGATIVE_SIDE || 
     704                                (smax == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_LEFT)) 
     705                        { 
     706                                if (branch->mLeft) 
     707                                        recInsert(branch->mLeft, rend); 
     708                                else 
     709                                        recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 
     710                        } 
     711                        else if (smin == Plane::POSITIVE_SIDE ||  
     712                                (smin == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_RIGHT)) 
     713                        { 
     714                                if (branch->mRight) 
     715                                        recInsert(branch->mRight, rend); 
     716                                else 
     717                                        recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 
     718                        } 
     719                } 
     720                else 
     721                { 
     722                        if (smin == Plane::NEGATIVE_SIDE && smax == Plane::NO_SIDE) 
     723                        { 
     724                                if (branch->mLeft) 
     725                                        recInsert(branch->mLeft, rend); 
     726                                else 
     727                                        recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 
     728                        } 
     729                        else if (smax == Plane::POSITIVE_SIDE && smin == Plane::NO_SIDE) 
     730                        { 
     731                                if (branch->mRight) 
     732                                        recInsert(branch->mRight, rend); 
     733                                else 
     734                                        recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 
     735                        } 
     736                        else 
     737                        { 
     738                                // to avoid SNAFUs, rebuild whole subtree 
     739                                //LogManager::getSingleton().logMessage("## Rebuilding subtree for insertion"); 
     740                                rebuildSubtree(node, rend); 
     741                        } 
     742                } 
     743        } 
     744} 
     745 
     746void KdTree::recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend) 
     747{ 
     748        //LogManager::getSingleton().logMessage("## Inserting into new subtree"); 
     749 
     750        AxisAlignedBox left, rigth, aabb; 
     751        PlaneEventList events; 
     752        int nObjects; 
     753         
     754        rend->computeScene(events, aabb, nObjects, false); 
     755 
     756        // override aabb 
     757        splitBox(*parent, left, rigth); 
     758        if (side == PlaneEvent::PES_LEFT) 
     759        { 
     760                aabb = left; 
     761                if (mBuildMethod == KDBM_RECURSIVE) 
     762                        parent->mLeft = recBuild(events, nObjects, aabb, parent); 
     763                else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
     764                        parent->mLeft = pqBuild(events, nObjects, aabb, parent); 
     765                else 
     766                { 
     767                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
     768                                "Invalid build method for the KdTree.", 
     769                                "KdTree::buildFromList"); 
     770                        parent->mLeft = 0; 
     771                } 
     772                 
     773        } 
     774        else if (side == PlaneEvent::PES_RIGHT) 
     775        { 
     776                aabb = rigth; 
     777                if (mBuildMethod == KDBM_RECURSIVE) 
     778                        parent->mRight = recBuild(events, nObjects, aabb, parent); 
     779                else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
     780                        parent->mRight = pqBuild(events, nObjects, aabb, parent); 
     781                else 
     782                { 
     783                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
     784                                "Invalid build method for the KdTree.", 
     785                                "KdTree::buildFromList"); 
     786                        parent->mRight = 0; 
     787                } 
     788        } 
     789} 
     790 
     791void KdTree::rebuildSubtree(KdTree::Node * node, KdRenderable * rend) 
     792{ 
     793        //LogManager::getSingleton().logMessage("## Rebuilding subtree"); 
     794 
     795        AxisAlignedBox aabb = node->mAABB; 
     796         
     797        KdRenderableList nodelist; 
     798        nodelist.push_back(rend); 
     799        addRendToList(node, nodelist); 
     800 
     801        if (node == mKdRoot) 
     802        { 
     803                OGRE_DELETE(mKdRoot); 
     804                mKdRoot = buildFromList(nodelist, 0, aabb); 
     805        } 
     806        else 
     807        { 
     808                KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 
     809 
     810                if (node == parent->mLeft) 
     811                { 
     812                        OGRE_DELETE(parent->mLeft); 
     813                        parent->mLeft = buildFromList(nodelist, parent, aabb); 
     814                } 
     815                else if (node == parent->mRight) 
     816                { 
     817                        OGRE_DELETE(parent->mRight); 
     818                        parent->mRight = buildFromList(nodelist, parent, aabb); 
     819                } 
     820                else 
    410821                { 
    411822                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
    412823                                "SNAFU while inserting KdRenderable into KdTree.", 
    413824                                "KdTree::recInsert" ); 
    414                         return; 
    415                 } 
    416  
    417                 if (node->isEmpty()) 
    418                 { 
    419                         if (node == mKdRoot) 
    420                         { 
    421                                 OGRE_DELETE(mKdRoot); 
    422                         }  
     825                } 
     826        } 
     827} 
     828 
     829// compute both AABB then return the requested one. 
     830void KdTree::splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right) 
     831{ 
     832        Vector3 bmin = parent.mAABB.getMinimum(); 
     833        Vector3 bmax = parent.mAABB.getMaximum(); 
     834        Real pos = - parent.mSplitPlane->d; 
     835        int dim = static_cast<int>(parent.mSplitPlane->normal.dotProduct(Vector3(0,1,2))); 
     836        // set corners which are the same as parent AABB 
     837        left.setMinimum(bmin); 
     838        right.setMaximum(bmax); 
     839        // modify "inner" corners 
     840        bmin[dim] = pos; 
     841        bmax[dim] = pos; 
     842        // set the corners on the split plane 
     843        left.setMaximum(bmax); 
     844        right.setMinimum(bmin); 
     845} 
     846 
     847void KdTree::addRendToList(KdTree::Node * node, KdRenderableList& nodelist) 
     848{ 
     849        if (node->isLeaf()) 
     850        { 
     851                KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
     852                KdRenderableList::iterator it  = leaf->mKdRenderables.begin(); 
     853                KdRenderableList::iterator end = leaf->mKdRenderables.end(); 
     854                while (it != end) 
     855                { 
     856                        nodelist.push_back(*it); 
     857                        it++; 
     858                } 
     859        } 
     860        else 
     861        { 
     862                KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
     863                if (branch->mLeft) 
     864                        addRendToList(branch->mLeft, nodelist); 
     865                if (branch->mRight) 
     866                        addRendToList(branch->mRight, nodelist); 
     867        } 
     868} 
     869 
     870/************************************************************************/ 
     871/* KdTree build functions                                               */ 
     872/************************************************************************/ 
     873 
     874void KdTree::build(KdRenderable * sceneRoot) 
     875{ 
     876        Timer *timer = Root::getSingleton().getTimer(); 
     877        unsigned long t1, t2, t3, t4; 
     878 
     879        mStats.clear(); 
     880         
     881        // data we want to collect 
     882        PlaneEventList events; 
     883        AxisAlignedBox aabb; 
     884        int nObjects = 0; 
     885 
     886        t1 = timer->getMicroseconds(); // DEBUG 
     887        sceneRoot->computeScene(events, aabb, nObjects); 
     888        t2 = timer->getMicroseconds(); // DEBUG 
     889        events.sort(); 
     890        t3 = timer->getMicroseconds(); // DEBUG 
     891 
     892        mStats.mNumSceneNodes = nObjects; 
     893 
     894        assert(! aabb.isNull() && "Teh stubid worldAABB iz NULL ... waht now?"); 
     895        // hack to avoid SNAFU with "2-dimensional" scene 
     896        aabb.merge(aabb.getMaximum()+Vector3(1,1,1)); 
     897        aabb.merge(aabb.getMinimum()+Vector3(-1,-1,-1)); 
     898 
     899        if (mBuildMethod == KDBM_RECURSIVE) 
     900                mKdRoot = recBuild(events, nObjects, aabb, 0); 
     901        else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
     902                mKdRoot = pqBuild(events, nObjects, aabb, 0); 
     903        else 
     904        { 
     905                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
     906                        "Invalid build method for the KdTree.", 
     907                        "KdTree::build"); 
     908                mKdRoot = 0; 
     909        } 
     910 
     911        t4 = timer->getMicroseconds(); // DEBUG 
     912 
     913        String method = "Invalid"; 
     914        if (mBuildMethod == KDBM_RECURSIVE) 
     915                method = "Recursive"; 
     916        else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
     917                method = "Priority Queue"; 
     918 
     919        mBuildLog->logMessage("######## SAH Statistics ########"); 
     920        mBuildLog->logMessage("Build Method: " + method); 
     921        mBuildLog->logMessage("Time for events build: " + StringConverter::toString(t2 - t1) + "µs"); 
     922        mBuildLog->logMessage("Time for events sort: " + StringConverter::toString(t3 - t2) + "µs"); 
     923        mBuildLog->logMessage("Time for tree build: " + StringConverter::toString(t4 - t3) + "µs"); 
     924        mBuildLog->logMessage("Total time: " + StringConverter::toString(t4 - t1) + "µs"); 
     925        mBuildLog->logMessage("Tree Depth: " + StringConverter::toString(mMaxDepth)); 
     926        mBuildLog->logMessage("Number of Objects: " + StringConverter::toString(mStats.mNumSceneNodes)); 
     927        mBuildLog->logMessage("Number of Leaves: " + StringConverter::toString(mStats.mNumLeaves)); 
     928        mBuildLog->logMessage("Number of Nodes: " + StringConverter::toString(mStats.mNumNodes)); 
     929        mBuildLog->logMessage("Total cost: " + StringConverter::toString(calcCost())); 
     930        mBuildLog->logMessage("################################"); 
     931} 
     932 
     933KdTree::Node * KdTree::buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb) 
     934{ 
     935        // data we want to collect 
     936        PlaneEventList events; 
     937        AxisAlignedBox nodeaabb; 
     938        int nObjects = 0; 
     939 
     940        KdRenderableList::iterator it = nodelist.begin(); 
     941        KdRenderableList::iterator end = nodelist.end(); 
     942        while (it != end) 
     943        { 
     944                (*it)->computeScene(events, nodeaabb, nObjects, false); 
     945                it++; 
     946        } 
     947 
     948        events.sort(); 
     949         
     950        // HACK 
     951        if (aabb.isNull()) 
     952        { 
     953                aabb = nodeaabb; 
     954        } 
     955 
     956        if (mBuildMethod == KDBM_RECURSIVE) 
     957                return recBuild(events, nObjects, aabb, parent); 
     958        else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
     959                return pqBuild(events, nObjects, aabb, parent); 
     960        else 
     961        { 
     962                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
     963                        "Invalid build method for the KdTree.", 
     964                        "KdTree::buildFromList"); 
     965                return 0; 
     966        } 
     967} 
     968 
     969KdTree::Node * KdTree::recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 
     970{ 
     971        // determine the depth we are on 
     972        int level = 0; 
     973        if (parent) 
     974        { 
     975                level = parent->getLevel() + 1; 
     976        } 
     977 
     978        /************************************************/ 
     979        /**************** BEGIN FINDPLANE ***************/ 
     980        /************************************************/ 
     981        // find optimal split plane and split node accordingly 
     982 
     983        // initialize 
     984        const int dim = 3; 
     985        int pStart, pOn, pEnd; 
     986        int nLeft[dim], nPlane[dim], nRight[dim]; 
     987        for (int i = 0; i < dim; i++) 
     988        { 
     989                nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 
     990        } 
     991 
     992        SplitInfo split, best; 
     993        best.cost = Math::POS_INFINITY; 
     994 
     995        PlaneEventList::iterator begin = events.begin(); 
     996        PlaneEventList::iterator end = events.end(); 
     997        PlaneEventList::iterator it = begin; 
     998        // try all planes to find the best one for the given set of objects 
     999        while (it != end) 
     1000        { 
     1001                PlaneEventList::iterator p = it; 
     1002                pStart = pOn = pEnd = 0; 
     1003                while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 
     1004                { 
     1005                        it++; pEnd++; 
     1006                } 
     1007                while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 
     1008                { 
     1009                        it++; pOn++; 
     1010                } 
     1011                while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 
     1012                { 
     1013                        it++; pStart++; 
     1014                } 
     1015                int d = p->getDimension(); 
     1016                nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 
     1017                p->SAH(aabb, nLeft[d], nPlane[d], nRight[d], split); 
     1018                if (split.cost < best.cost) 
     1019                { 
     1020                        best = split; 
     1021                } 
     1022                nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 
     1023        } 
     1024 
     1025        /************************************************/ 
     1026        /**************** BEGIN TERMINATE ***************/ 
     1027        /************************************************/ 
     1028        // check terminating condition 
     1029        if (best.cost > PlaneEvent::KI*nObjects || level >= mMaxDepth) 
     1030        { 
     1031                // Terminating condition reached, create leaf and add renderables to list 
     1032                KdTree::Leaf * leaf = new KdTree::Leaf(this, level, aabb, parent); 
     1033                KdRenderable *rend; 
     1034                it = begin; 
     1035                while (it != end) 
     1036                { 
     1037                        rend = it->getRenderable(); 
     1038                        rend->setClassified(false); 
     1039                        if (rend->attachTo(leaf, this)) 
     1040                        { 
     1041                                leaf->insert(rend); 
     1042                        } 
     1043                        it++; 
     1044                } 
     1045                // update stats 
     1046                ++ mStats.mNumNodes; 
     1047                ++ mStats.mNumLeaves; 
     1048                // update bounding box 
     1049                leaf->_updateBounds(false); 
     1050                return leaf; 
     1051        } 
     1052 
     1053        /************************************************/ 
     1054        /**************** BEGIN CLASSIFY ****************/ 
     1055        /************************************************/ 
     1056        // split the event list in left and right sub-lists 
     1057        else 
     1058        { 
     1059                PlaneEventList eventsRight, eventsLeft; 
     1060                it = begin; 
     1061                // slightly redundant, since we mark each renderable up to 6 times 
     1062                while (it != end) 
     1063                { 
     1064                        it->getRenderable()->setSide(PlaneEvent::PES_BOTH); 
     1065                        it->getRenderable()->setClassified(false); 
     1066                        it++; 
     1067                } 
     1068                // now classify all renderables. do they belong to the left child, the right child or both? 
     1069                it = begin; 
     1070                while (it != end) 
     1071                { 
     1072                        it->classify(best.event, best.side); 
     1073                        it++; 
     1074                } 
     1075                // divide the event lists 
     1076                int nLeftS = 0, nRightS = 0, nBothS = 0; 
     1077                it = begin; 
     1078                while (it != end) 
     1079                { 
     1080                        // right-only nodes go in right list 
     1081                        if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 
     1082                        { 
     1083                                if (!it->getRenderable()->isClassified()) 
     1084                                { 
     1085                                        it->getRenderable()->setClassified(true); 
     1086                                        nRightS++; 
     1087                                } 
     1088                                eventsRight.push_back(*it); 
     1089                        } 
     1090                        // left-only nodes go in left list 
     1091                        else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 
     1092                        { 
     1093                                if (!it->getRenderable()->isClassified()) 
     1094                                { 
     1095                                        it->getRenderable()->setClassified(true); 
     1096                                        nLeftS++; 
     1097                                } 
     1098                                eventsLeft.push_back(*it); 
     1099                        } 
     1100                        // remaining nodes go in both lists, bust must be clipped to prevent 
     1101                        // events from lying outside the new nodes aabb 
    4231102                        else 
    4241103                        { 
    425                                 KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 
    426                                 if (node == parent->mLeft) 
     1104                                if (!it->getRenderable()->isClassified()) 
    4271105                                { 
    428                                         OGRE_DELETE(parent->mLeft); 
     1106                                        it->getRenderable()->setClassified(true); 
     1107                                        nBothS++; 
    4291108                                } 
    430                                 else if (node == parent->mRight) 
    431                                 { 
    432                                         OGRE_DELETE(parent->mRight); 
    433                                 } 
    434                                 recDelete(parent); 
    435                         } 
    436                 } 
    437         } 
    438  
    439         void KdTree::insert(KdRenderable * rend) 
    440         { 
    441                 // make sure the tree exists 
    442                 if (mKdRoot) 
    443                 { 
    444                         // make sure the renderable is inside the world bounding box 
    445                         AxisAlignedBox aabb = rend->getBoundingBox(); 
    446                         AxisAlignedBox isect = mKdRoot->mAABB.intersection(aabb); 
    447                         if (isect.getMinimum() == aabb.getMinimum() && isect.getMaximum() == aabb.getMaximum()) 
    448                         { 
    449                                 recInsert(mKdRoot, rend); 
    450                         } 
    451                         else 
    452                         { 
    453                                 //LogManager::getSingleton().logMessage("Inserted node outside of world AABB."); 
    454                                 KdRenderableList nodelist; 
    455                                 nodelist.push_back(rend); 
    456                                 addRendToList(mKdRoot, nodelist); 
    457                                 OGRE_DELETE(mKdRoot); 
    458                                 mKdRoot = buildFromList(nodelist, 0, AxisAlignedBox()); 
    459                         } 
    460                 } 
    461                 // otherwise build a new one 
    462                 else 
    463                 { 
    464                         build(rend); 
    465                 } 
    466         } 
    467  
    468         void KdTree::recInsert(KdTree::Node * node, KdRenderable * rend) 
    469         { 
    470                 if (node == 0) // DEBUG 
    471                 { 
    472                         OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
    473                                 "SNAFU while inserting KdRenderable into KdTree.", 
    474                                 "KdTree::recInsert" ); 
    475                         return; 
    476                 } 
    477  
    478                 // rebuild the leaf/replace with subtree ... 
    479                 if (node->isLeaf()) 
    480                 { 
    481                         //LogManager::getSingleton().logMessage("## Replacing leaf."); 
    482                         rebuildSubtree(node, rend); 
    483                 } 
    484                 else 
    485                 { 
    486                         KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
    487                         AxisAlignedBox aabb = rend->getBoundingBox(); 
    488                         Plane::Side smin = branch->mSplitPlane->getSide(aabb.getMinimum()); 
    489                         Plane::Side smax = branch->mSplitPlane->getSide(aabb.getMaximum()); 
    490                         if (smin == smax) 
    491                         { 
    492                                 if (smax == Plane::NEGATIVE_SIDE || 
    493                                         (smax == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_LEFT)) 
    494                                 { 
    495                                         if (branch->mLeft) 
    496                                                 recInsert(branch->mLeft, rend); 
    497                                         else 
    498                                                 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 
    499                                 } 
    500                                 else if (smin == Plane::POSITIVE_SIDE ||  
    501                                         (smin == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_RIGHT)) 
    502                                 { 
    503                                         if (branch->mRight) 
    504                                                 recInsert(branch->mRight, rend); 
    505                                         else 
    506                                                 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 
    507                                 } 
    508                         } 
    509                         else 
    510                         { 
    511                                 if (smin == Plane::NEGATIVE_SIDE && smax == Plane::NO_SIDE) 
    512                                 { 
    513                                         if (branch->mLeft) 
    514                                                 recInsert(branch->mLeft, rend); 
    515                                         else 
    516                                                 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 
    517                                 } 
    518                                 else if (smax == Plane::POSITIVE_SIDE && smin == Plane::NO_SIDE) 
    519                                 { 
    520                                         if (branch->mRight) 
    521                                                 recInsert(branch->mRight, rend); 
    522                                         else 
    523                                                 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 
    524                                 } 
    525                                 else 
    526                                 { 
    527                                         // to avoid SNAFUs, rebuild whole subtree 
    528                                         //LogManager::getSingleton().logMessage("## Rebuilding subtree for insertion"); 
    529                                         rebuildSubtree(node, rend); 
    530                                 } 
    531                         } 
    532                 } 
    533         } 
    534  
    535         void KdTree::recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend) 
    536         { 
    537                 //LogManager::getSingleton().logMessage("## Inserting into new subtree"); 
    538  
    539                 AxisAlignedBox left, rigth, aabb; 
    540                 PlaneEventList events; 
    541                 int nObjects; 
    542                  
    543                 rend->computeScene(events, aabb, nObjects, false); 
    544  
    545                 // override aabb 
    546                 splitBox(*parent, left, rigth); 
    547                 if (side == PlaneEvent::PES_LEFT) 
    548                 { 
    549                         aabb = left; 
    550                         if (mBuildMethod == KDBM_RECURSIVE) 
    551                                 parent->mLeft = recBuild(events, nObjects, aabb, parent); 
    552                         else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
    553                                 parent->mLeft = pqBuild(events, nObjects, aabb, parent); 
    554                         else 
    555                         { 
    556                                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
    557                                         "Invalid build method for the KdTree.", 
    558                                         "KdTree::buildFromList"); 
    559                                 parent->mLeft = 0; 
    560                         } 
    561                          
    562                 } 
    563                 else if (side == PlaneEvent::PES_RIGHT) 
    564                 { 
    565                         aabb = rigth; 
    566                         if (mBuildMethod == KDBM_RECURSIVE) 
    567                                 parent->mRight = recBuild(events, nObjects, aabb, parent); 
    568                         else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
    569                                 parent->mRight = pqBuild(events, nObjects, aabb, parent); 
    570                         else 
    571                         { 
    572                                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
    573                                         "Invalid build method for the KdTree.", 
    574                                         "KdTree::buildFromList"); 
    575                                 parent->mRight = 0; 
    576                         } 
    577                 } 
    578         } 
    579  
    580         void KdTree::rebuildSubtree(KdTree::Node * node, KdRenderable * rend) 
    581         { 
    582                 //LogManager::getSingleton().logMessage("## Rebuilding subtree"); 
    583  
    584                 AxisAlignedBox aabb = node->mAABB; 
    585                  
    586                 KdRenderableList nodelist; 
    587                 nodelist.push_back(rend); 
    588                 addRendToList(node, nodelist); 
    589  
    590                 if (node == mKdRoot) 
    591                 { 
    592                         OGRE_DELETE(mKdRoot); 
    593                         mKdRoot = buildFromList(nodelist, 0, aabb); 
    594                 } 
    595                 else 
    596                 { 
    597                         KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 
    598  
    599                         if (node == parent->mLeft) 
    600                         { 
    601                                 OGRE_DELETE(parent->mLeft); 
    602                                 parent->mLeft = buildFromList(nodelist, parent, aabb); 
    603                         } 
    604                         else if (node == parent->mRight) 
    605                         { 
    606                                 OGRE_DELETE(parent->mRight); 
    607                                 parent->mRight = buildFromList(nodelist, parent, aabb); 
    608                         } 
    609                         else 
    610                         { 
    611                                 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
    612                                         "SNAFU while inserting KdRenderable into KdTree.", 
    613                                         "KdTree::recInsert" ); 
    614                         } 
    615                 } 
    616         } 
    617  
    618         // compute both AABB then return the requested one. 
    619         void KdTree::splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right) 
    620         { 
    621                 Vector3 bmin = parent.mAABB.getMinimum(); 
    622                 Vector3 bmax = parent.mAABB.getMaximum(); 
    623                 Real pos = - parent.mSplitPlane->d; 
    624                 int dim = static_cast<int>(parent.mSplitPlane->normal.dotProduct(Vector3(0,1,2))); 
    625                 // set corners which are the same as parent AABB 
    626                 left.setMinimum(bmin); 
    627                 right.setMaximum(bmax); 
    628                 // modify "inner" corners 
    629                 bmin[dim] = pos; 
    630                 bmax[dim] = pos; 
    631                 // set the corners on the split plane 
    632                 left.setMaximum(bmax); 
    633                 right.setMinimum(bmin); 
    634         } 
    635  
    636         void KdTree::addRendToList(KdTree::Node * node, KdRenderableList& nodelist) 
    637         { 
    638                 if (node->isLeaf()) 
    639                 { 
    640                         KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
    641                         KdRenderableList::iterator it  = leaf->mKdRenderables.begin(); 
    642                         KdRenderableList::iterator end = leaf->mKdRenderables.end(); 
    643                         while (it != end) 
    644                         { 
    645                                 nodelist.push_back(*it); 
    646                                 it++; 
    647                         } 
    648                 } 
    649                 else 
    650                 { 
    651                         KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
    652                         if (branch->mLeft) 
    653                                 addRendToList(branch->mLeft, nodelist); 
    654                         if (branch->mRight) 
    655                                 addRendToList(branch->mRight, nodelist); 
    656                 } 
    657         } 
    658  
    659         /************************************************************************/ 
    660         /* KdTree build functions                                               */ 
    661         /************************************************************************/ 
    662  
    663         void KdTree::build(KdRenderable * sceneRoot) 
    664         { 
    665                 Timer *timer = Root::getSingleton().getTimer(); 
    666                 unsigned long t1, t2, t3, t4; 
    667  
    668                 mStats.clear(); 
    669                  
    670                 // data we want to collect 
    671                 PlaneEventList events; 
    672                 AxisAlignedBox aabb; 
    673                 int nObjects = 0; 
    674  
    675                 t1 = timer->getMicroseconds(); // DEBUG 
    676                 sceneRoot->computeScene(events, aabb, nObjects); 
    677                 t2 = timer->getMicroseconds(); // DEBUG 
    678                 events.sort(); 
    679                 t3 = timer->getMicroseconds(); // DEBUG 
    680  
    681                 mStats.mNumSceneNodes = nObjects; 
    682  
    683                 assert(! aabb.isNull() && "Teh stubid worldAABB iz NULL ... waht now?"); 
    684                 // hack to avoid SNAFU with "2-dimensional" scene 
    685                 aabb.merge(aabb.getMaximum()+Vector3(1,1,1)); 
    686                 aabb.merge(aabb.getMinimum()+Vector3(-1,-1,-1)); 
    687  
    688                 if (mBuildMethod == KDBM_RECURSIVE) 
    689                         mKdRoot = recBuild(events, nObjects, aabb, 0); 
    690                 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
    691                         mKdRoot = pqBuild(events, nObjects, aabb, 0); 
    692                 else 
    693                 { 
    694                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
    695                                 "Invalid build method for the KdTree.", 
    696                                 "KdTree::build"); 
    697                         mKdRoot = 0; 
    698                 } 
    699  
    700                 t4 = timer->getMicroseconds(); // DEBUG 
    701  
    702                 String method = "Invalid"; 
    703                 if (mBuildMethod == KDBM_RECURSIVE) 
    704                         method = "Recursive"; 
    705                 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
    706                         method = "Priority Queue"; 
    707  
    708                 mBuildLog->logMessage("######## SAH Statistics ########"); 
    709                 mBuildLog->logMessage("Build Method: " + method); 
    710                 mBuildLog->logMessage("Time for events build: " + StringConverter::toString(t2 - t1) + "µs"); 
    711                 mBuildLog->logMessage("Time for events sort: " + StringConverter::toString(t3 - t2) + "µs"); 
    712                 mBuildLog->logMessage("Time for tree build: " + StringConverter::toString(t4 - t3) + "µs"); 
    713                 mBuildLog->logMessage("Total time: " + StringConverter::toString(t4 - t1) + "µs"); 
    714                 mBuildLog->logMessage("Tree Depth: " + StringConverter::toString(mMaxDepth)); 
    715                 mBuildLog->logMessage("Number of Objects: " + StringConverter::toString(mStats.mNumSceneNodes)); 
    716                 mBuildLog->logMessage("Number of Leaves: " + StringConverter::toString(mStats.mNumLeaves)); 
    717                 mBuildLog->logMessage("Number of Nodes: " + StringConverter::toString(mStats.mNumNodes)); 
    718                 mBuildLog->logMessage("Total cost: " + StringConverter::toString(calcCost())); 
    719                 mBuildLog->logMessage("################################"); 
    720         } 
    721  
    722         KdTree::Node * KdTree::buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb) 
    723         { 
    724                 // data we want to collect 
    725                 PlaneEventList events; 
    726                 AxisAlignedBox nodeaabb; 
    727                 int nObjects = 0; 
    728  
    729                 KdRenderableList::iterator it = nodelist.begin(); 
    730                 KdRenderableList::iterator end = nodelist.end(); 
    731                 while (it != end) 
    732                 { 
    733                         (*it)->computeScene(events, nodeaabb, nObjects, false); 
     1109                                eventsRight.push_back(it->clip(best.bright, best.event.getDimension())); 
     1110                                eventsLeft.push_back(it->clip(best.bleft, best.event.getDimension())); 
     1111                        } 
    7341112                        it++; 
    7351113                } 
    7361114 
    737                 events.sort(); 
    738                  
    739                 // HACK 
    740                 if (aabb.isNull()) 
    741                 { 
    742                         aabb = nodeaabb; 
    743                 } 
    744  
    745                 if (mBuildMethod == KDBM_RECURSIVE) 
    746                         return recBuild(events, nObjects, aabb, parent); 
    747                 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 
    748                         return pqBuild(events, nObjects, aabb, parent); 
    749                 else 
    750                 { 
    751                         OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,  
    752                                 "Invalid build method for the KdTree.", 
    753                                 "KdTree::buildFromList"); 
    754                         return 0; 
    755                 } 
    756         } 
    757  
    758         KdTree::Node * KdTree::recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 
    759         { 
     1115                // create a new branch node and continue recursion 
     1116                KdTree::Branch * branch = new KdTree::Branch(this, level, aabb, parent,  
     1117                        best.event.getSplitPlane(), best.side); 
     1118 
     1119                // now create the child nodes and continue recursion 
     1120                if (eventsLeft.size() > 0) 
     1121                { 
     1122                        branch->mLeft = recBuild(eventsLeft, nLeftS + nBothS, best.bleft, branch); 
     1123                } 
     1124                if (eventsRight.size() > 0) 
     1125                { 
     1126                        branch->mRight = recBuild(eventsRight, nBothS + nRightS, best.bright, branch); 
     1127                } 
     1128 
     1129                // update stats 
     1130                ++ mStats.mNumNodes; 
     1131 
     1132                // update bounding box 
     1133                branch->_updateBounds(false); 
     1134 
     1135                return branch; 
     1136        } 
     1137} 
     1138 
     1139KdTree::Node * KdTree::pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 
     1140{ 
     1141        SplitCandidatePQ pqueue; 
     1142        Real globalTreeCost; 
     1143        Real globalSA; 
     1144 
     1145        KdTree::Node * newNode = 0, * topNode = 0; 
     1146        // init global tree cost 
     1147        globalTreeCost = PlaneEvent::KI * nObjects; 
     1148        globalSA = PlaneEvent::surfaceArea(aabb); 
     1149 
     1150        PlaneEventList * e = new PlaneEventList(events); 
     1151 
     1152        // inital split candidate 
     1153        SplitInfo * best = pqFindPlane(e, nObjects, aabb, globalSA); 
     1154        SplitCandidate splitcandidate(e, nObjects, aabb, parent, globalTreeCost,  
     1155                globalTreeCost - best->cost, best, PlaneEvent::PES_BOTH); 
     1156        pqueue.push(splitcandidate); 
     1157 
     1158 
     1159        /*** BEGIN ITERATIVE BUILD ***/ 
     1160        while (!pqueue.empty()) 
     1161        { 
     1162                SplitCandidate sc = pqueue.top(); 
     1163                pqueue.pop(); 
     1164 
    7601165                // determine the depth we are on 
    7611166                int level = 0; 
    762                 if (parent) 
    763                 { 
    764                         level = parent->getLevel() + 1; 
    765                 } 
    766  
    767                 /************************************************/ 
    768                 /**************** BEGIN FINDPLANE ***************/ 
    769                 /************************************************/ 
    770                 // find optimal split plane and split node accordingly 
    771  
    772                 // initialize 
    773                 const int dim = 3; 
    774                 int pStart, pOn, pEnd; 
    775                 int nLeft[dim], nPlane[dim], nRight[dim]; 
    776                 for (int i = 0; i < dim; i++) 
    777                 { 
    778                         nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 
    779                 } 
    780  
    781                 SplitInfo split, best; 
    782                 best.cost = Math::POS_INFINITY; 
    783  
    784                 PlaneEventList::iterator begin = events.begin(); 
    785                 PlaneEventList::iterator end = events.end(); 
    786                 PlaneEventList::iterator it = begin; 
    787                 // try all planes to find the best one for the given set of objects 
    788                 while (it != end) 
    789                 { 
    790                         PlaneEventList::iterator p = it; 
    791                         pStart = pOn = pEnd = 0; 
    792                         while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 
    793                         { 
    794                                 it++; pEnd++; 
    795                         } 
    796                         while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 
    797                         { 
    798                                 it++; pOn++; 
    799                         } 
    800                         while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 
    801                         { 
    802                                 it++; pStart++; 
    803                         } 
    804                         int d = p->getDimension(); 
    805                         nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 
    806                         p->SAH(aabb, nLeft[d], nPlane[d], nRight[d], split); 
    807                         if (split.cost < best.cost) 
    808                         { 
    809                                 best = split; 
    810                         } 
    811                         nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 
     1167                if (sc.parent) 
     1168                { 
     1169                        level = sc.parent->getLevel() + 1; 
    8121170                } 
    8131171 
     
    8161174                /************************************************/ 
    8171175                // check terminating condition 
    818                 if (best.cost > PlaneEvent::KI*nObjects || level >= mMaxDepth) 
     1176                if (sc.decrease < 0.0 || level >= mMaxDepth) 
    8191177                { 
    8201178                        // Terminating condition reached, create leaf and add renderables to list 
    821                         KdTree::Leaf * leaf = new KdTree::Leaf(this, level, aabb, parent); 
     1179                        KdTree::Leaf * leaf = new KdTree::Leaf(this, level, sc.aabb, sc.parent); 
    8221180                        KdRenderable *rend; 
    823                         it = begin; 
     1181                        PlaneEventList::iterator begin = sc.events->begin(); 
     1182                        PlaneEventList::iterator end = sc.events->end(); 
     1183                        PlaneEventList::iterator it = begin; 
    8241184                        while (it != end) 
    8251185                        { 
     
    8321192                                it++; 
    8331193                        } 
     1194                        newNode = leaf; 
     1195                        if (!topNode) 
     1196                                topNode = leaf; 
    8341197                        // update stats 
    8351198                        ++ mStats.mNumNodes; 
    8361199                        ++ mStats.mNumLeaves; 
    837                         // update bounding box 
    838                         leaf->_updateBounds(false); 
    839                         return leaf; 
    8401200                } 
    8411201 
     
    8431203                /**************** BEGIN CLASSIFY ****************/ 
    8441204                /************************************************/ 
    845                 // split the event list in left and right sub-lists 
    8461205                else 
    8471206                { 
    848                         PlaneEventList eventsRight, eventsLeft; 
    849                         it = begin; 
     1207                        PlaneEventList * eventsLeft = new PlaneEventList(); 
     1208                        PlaneEventList * eventsRight = new PlaneEventList(); 
     1209                        PlaneEventList::iterator begin = sc.events->begin(); 
     1210                        PlaneEventList::iterator end = sc.events->end(); 
     1211                        PlaneEventList::iterator it = begin; 
    8501212                        // slightly redundant, since we mark each renderable up to 6 times 
    8511213                        while (it != end) 
     
    8551217                                it++; 
    8561218                        } 
     1219 
    8571220                        // now classify all renderables. do they belong to the left child, the right child or both? 
    8581221                        it = begin; 
    8591222                        while (it != end) 
    8601223                        { 
    861                                 it->classify(best.event, best.side); 
     1224                                it->classify(sc.best->event, sc.best->side); 
    8621225                                it++; 
    8631226                        } 
     1227 
    8641228                        // divide the event lists 
    8651229                        int nLeftS = 0, nRightS = 0, nBothS = 0; 
     
    8671231                        while (it != end) 
    8681232                        { 
    869                                 // right-only nodes go in right list 
     1233                                // right-only events go in the right list 
    8701234                                if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 
    8711235                                { 
     
    8751239                                                nRightS++; 
    8761240                                        } 
    877                                         eventsRight.push_back(*it); 
     1241 
     1242                                        eventsRight->push_back(*it); 
    8781243                                } 
    879                                 // left-only nodes go in left list 
     1244                                // left-only events go in the left list 
    8801245                                else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 
    8811246                                { 
     
    8851250                                                nLeftS++; 
    8861251                                        } 
    887                                         eventsLeft.push_back(*it); 
     1252                                        eventsLeft->push_back(*it); 
    8881253                                } 
    889                                 // remaining nodes go in both lists, bust must be clipped to prevent 
    890                                 // events from lying outside the new nodes aabb 
     1254                                // the rest goes in both lists after being clipped 
    8911255                                else 
    8921256                                { 
     
    8961260                                                nBothS++; 
    8971261                                        } 
    898                                         eventsRight.push_back(it->clip(best.bright, best.event.getDimension())); 
    899                                         eventsLeft.push_back(it->clip(best.bleft, best.event.getDimension())); 
     1262 
     1263                                        eventsRight->push_back(it->clip(sc.best->bright, sc.best->event.getDimension())); 
     1264                                        eventsLeft->push_back(it->clip(sc.best->bleft, sc.best->event.getDimension())); 
    9001265                                } 
    9011266                                it++; 
    9021267                        } 
    9031268 
    904                         // create a new branch node and continue recursion 
    905                         KdTree::Branch * branch = new KdTree::Branch(this, level, aabb, parent,  
    906                                 best.event.getSplitPlane(), best.side); 
    907  
    908                         // now create the child nodes and continue recursion 
    909                         if (eventsLeft.size() > 0) 
    910                         { 
    911                                 branch->mLeft = recBuild(eventsLeft, nLeftS + nBothS, best.bleft, branch); 
    912                         } 
    913                         if (eventsRight.size() > 0) 
    914                         { 
    915                                 branch->mRight = recBuild(eventsRight, nBothS + nRightS, best.bright, branch); 
    916                         } 
     1269                        // create a new branch node 
     1270                        KdTree::Branch * branch = new KdTree::Branch(this, level, sc.aabb, sc.parent,  
     1271                                sc.best->event.getSplitPlane(), sc.best->side); 
     1272 
     1273                        globalTreeCost -= sc.decrease; 
     1274 
     1275 
     1276                        // now for each potential child node, compute the split plane and the cost decrease 
     1277                        // and place them in the queue 
     1278                        if (eventsLeft->size() > 0) 
     1279                        { 
     1280                                best = pqFindPlane(eventsLeft, nLeftS + nBothS, sc.best->bleft, globalSA); 
     1281                                Real old = PlaneEvent::surfaceArea(sc.best->bleft)/globalSA*PlaneEvent::KI*(nLeftS + nBothS); 
     1282                                SplitCandidate scleft(eventsLeft, nLeftS + nBothS, sc.best->bleft,  
     1283                                        branch, old, old - best->cost, best, PlaneEvent::PES_LEFT); 
     1284                                pqueue.push(scleft); 
     1285                        } 
     1286                        // cleanup 
     1287                        else 
     1288                        { 
     1289                                delete eventsLeft; 
     1290                        } 
     1291 
     1292                        if (eventsRight->size() > 0) 
     1293                        { 
     1294                                best = pqFindPlane(eventsRight, nBothS + nRightS, sc.best->bright, globalSA); 
     1295                                Real old = PlaneEvent::surfaceArea(sc.best->bright)/globalSA*PlaneEvent::KI*(nBothS + nRightS); 
     1296                                SplitCandidate scright(eventsRight, nBothS + nRightS, sc.best->bright,  
     1297                                        branch, old, old - best->cost, best, PlaneEvent::PES_RIGHT); 
     1298                                pqueue.push(scright); 
     1299                        } 
     1300                        // cleanup 
     1301                        else 
     1302                        { 
     1303                                delete eventsRight; 
     1304                        } 
     1305 
     1306                        newNode = branch; 
     1307                        if (!topNode) 
     1308                                topNode = branch; 
     1309 
    9171310 
    9181311                        // update stats 
    9191312                        ++ mStats.mNumNodes; 
    920  
    921                         // update bounding box 
    922                         branch->_updateBounds(false); 
    923  
    924                         return branch; 
    925                 } 
    926         } 
    927  
    928         KdTree::Node * KdTree::pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 
    929         { 
    930                 SplitCandidatePQ pqueue; 
    931                 Real globalTreeCost; 
    932                 Real globalSA; 
    933  
    934                 KdTree::Node * newNode = 0, * topNode = 0; 
    935                 // init global tree cost 
    936                 globalTreeCost = PlaneEvent::KI * nObjects; 
    937                 globalSA = PlaneEvent::surfaceArea(aabb); 
    938  
    939                 PlaneEventList * e = new PlaneEventList(events); 
    940  
    941                 // inital split candidate 
    942                 SplitInfo * best = pqFindPlane(e, nObjects, aabb, globalSA); 
    943                 SplitCandidate splitcandidate(e, nObjects, aabb, parent, globalTreeCost,  
    944                         globalTreeCost - best->cost, best, PlaneEvent::PES_BOTH); 
    945                 pqueue.push(splitcandidate); 
    946  
    947  
    948                 /*** BEGIN ITERATIVE BUILD ***/ 
    949                 while (!pqueue.empty()) 
    950                 { 
    951                         SplitCandidate sc = pqueue.top(); 
    952                         pqueue.pop(); 
    953  
    954                         // determine the depth we are on 
    955                         int level = 0; 
    956                         if (sc.parent) 
    957                         { 
    958                                 level = sc.parent->getLevel() + 1; 
    959                         } 
    960  
    961                         /************************************************/ 
    962                         /**************** BEGIN TERMINATE ***************/ 
    963                         /************************************************/ 
    964                         // check terminating condition 
    965                         if (sc.decrease < 0.0 || level >= mMaxDepth) 
    966                         { 
    967                                 // Terminating condition reached, create leaf and add renderables to list 
    968                                 KdTree::Leaf * leaf = new KdTree::Leaf(this, level, sc.aabb, sc.parent); 
    969                                 KdRenderable *rend; 
    970                                 PlaneEventList::iterator begin = sc.events->begin(); 
    971                                 PlaneEventList::iterator end = sc.events->end(); 
    972                                 PlaneEventList::iterator it = begin; 
    973                                 while (it != end) 
     1313                } 
     1314 
     1315                // attach new node to parent 
     1316                if (sc.parent) 
     1317                { 
     1318                        if (sc.side == PlaneEvent::PES_LEFT) 
     1319                        { 
     1320                                sc.parent->mLeft = newNode; 
     1321                        } 
     1322                        else if (sc.side == PlaneEvent::PES_RIGHT) 
     1323                        { 
     1324                                sc.parent->mRight = newNode; 
     1325                        } 
     1326                        else 
     1327                        { 
     1328                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
     1329                                        "PQBUILD SNAFU - CHILD I AM NOT LEFT NOR RIGHT","KdTree::pqBuild"); 
     1330                        } 
     1331                } 
     1332 
     1333                // update bounding boxes when geometry (leaf) was added 
     1334                if (newNode->isLeaf()) 
     1335                        newNode->_updateBounds(); 
     1336 
     1337                //cleanup 
     1338                OGRE_DELETE(sc.events); 
     1339                OGRE_DELETE(sc.best); 
     1340        } 
     1341        mBuildLog->logMessage("Cost after PQBUILD €" + StringConverter::toString(globalTreeCost)); 
     1342        return topNode; 
     1343} 
     1344 
     1345//------------------------------------------------------------------------- 
     1346SplitInfo * KdTree::pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA) 
     1347{ 
     1348        static const int dim = 3; 
     1349        int pStart, pOn, pEnd; 
     1350        int nLeft[dim], nPlane[dim], nRight[dim]; 
     1351        for (int i = 0; i < dim; i++) 
     1352        { 
     1353                nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 
     1354        } 
     1355 
     1356        SplitInfo split, best; 
     1357        best.cost = Math::POS_INFINITY; 
     1358 
     1359        Real parentSA = PlaneEvent::surfaceArea(aabb); 
     1360 
     1361        PlaneEventList::iterator begin = events->begin(); 
     1362        PlaneEventList::iterator end = events->end(); 
     1363        PlaneEventList::iterator it = begin; 
     1364        // try all planes to find the best one for the given set of objects 
     1365        while (it != end) 
     1366        { 
     1367                PlaneEventList::iterator p = it; 
     1368                pStart = pOn = pEnd = 0; 
     1369                while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 
     1370                { 
     1371                        it++; pEnd++; 
     1372                } 
     1373                while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 
     1374                { 
     1375                        it++; pOn++; 
     1376                } 
     1377                while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 
     1378                { 
     1379                        it++; pStart++; 
     1380                } 
     1381                int d = p->getDimension(); 
     1382                nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 
     1383                p->pqSAH(globalSA, parentSA, nLeft[d], nPlane[d], nRight[d], aabb, split); 
     1384                if (split.cost < best.cost) 
     1385                { 
     1386                        best = split; 
     1387                } 
     1388                nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 
     1389        } 
     1390        return new SplitInfo(best); 
     1391} 
     1392 
     1393/************************************************************************/ 
     1394/* KdTree rendering functions                                           */ 
     1395/************************************************************************/ 
     1396 
     1397//------------------------------------------------------------------------- 
     1398void KdTree::queueVisibleObjects(KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters,  
     1399        bool showBoxes, KdTree::NodeList& visibleNodes) 
     1400{ 
     1401        // debug 
     1402        //cam->mNumVisQueries = 0; 
     1403 
     1404        if (mKdRoot) 
     1405                recQueueVisibleObjects(mKdRoot, Root::getSingleton().getCurrentFrameNumber(), 
     1406                        cam, queue, onlyShadowCasters, showBoxes, visibleNodes); 
     1407 
     1408        //mBuildLog->logMessage("Frame # " + StringConverter::toString(Root::getSingleton().getCurrentFrameNumber()) + 
     1409        //      " ," + StringConverter::toString(cam->mNumVisQueries) + " vis queries"); 
     1410} 
     1411 
     1412//------------------------------------------------------------------------- 
     1413void KdTree::recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame,  
     1414        KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes,  
     1415        KdTree::NodeList& visibleNodes, bool fullVis) 
     1416{ 
     1417        KdTreeCamera::NodeVisibility vis = KdTreeCamera::KDNV_PART; 
     1418        // test visibility 
     1419        //if (cam->isVisible(node->mAABB)) 
     1420        if (fullVis ||  
     1421                ((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 
     1422                //((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 
     1423        { 
     1424                visibleNodes.push_back(node); 
     1425 
     1426                bool v = (fullVis || vis == KdTreeCamera::KDNV_FULL); 
     1427                node->queueVisibleObjects(currentFrame, cam, queue, onlyShadowCasters, showBoxes, v); 
     1428 
     1429                if (!v) 
     1430                { 
     1431 
     1432                        if (node->getLeftChild()) 
     1433                                recQueueVisibleObjects(node->getLeftChild(), currentFrame,  
     1434                                cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 
     1435                        if (node->getRightChild()) 
     1436                                recQueueVisibleObjects(node->getRightChild(), currentFrame,  
     1437                                cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 
     1438                } 
     1439        } 
     1440} 
     1441 
     1442//------------------------------------------------------------------------- 
     1443void KdTree::setEnhancedVis(bool enh) 
     1444{ 
     1445        if (enh) 
     1446                getVisibility = &KdTreeCamera::getVisibilityEnhanced; 
     1447        else 
     1448                getVisibility = &KdTreeCamera::getVisibilitySimple; 
     1449} 
     1450 
     1451//------------------------------------------------------------------------- 
     1452bool KdTree::getEnhancedVis() 
     1453{ 
     1454        return getVisibility == &KdTreeCamera::getVisibilityEnhanced; 
     1455} 
     1456 
     1457//------------------------------------------------------------------------- 
     1458//void KdTree::findVisibleNodes(NodeList& visibleNodes, Camera * cam) 
     1459//{ 
     1460//      if (mKdRoot) 
     1461//              recFindVisibleNodes(mKdRoot, visibleNodes, cam); 
     1462//} 
     1463 
     1464////------------------------------------------------------------------------- 
     1465//void KdTree::recFindVisibleNodes(KdTree::Node * node, NodeList& visibleNodes, Camera * cam) 
     1466//{ 
     1467//      // test visibility 
     1468//      if (cam->isVisible(node->mAABB)) 
     1469//      { 
     1470//              visibleNodes.push_back(node); 
     1471 
     1472//              if (node->getLeftChild()) 
     1473//                      recFindVisibleNodes(node->getLeftChild(), visibleNodes, cam); 
     1474//              if (node->getRightChild()) 
     1475//                      recFindVisibleNodes(node->getRightChild(), visibleNodes, cam); 
     1476//      } 
     1477//} 
     1478 
     1479void KdTree::findNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude) 
     1480{ 
     1481        if (mKdRoot) 
     1482                recFindNodesIn(box, list, exclude, mKdRoot); 
     1483} 
     1484 
     1485void KdTree::findNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude) 
     1486{ 
     1487        if (mKdRoot) 
     1488                recFindNodesIn(sphere, list, exclude, mKdRoot); 
     1489} 
     1490 
     1491void KdTree::findNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude) 
     1492{ 
     1493        if (mKdRoot) 
     1494                recFindNodesIn(volume, list, exclude, mKdRoot); 
     1495} 
     1496 
     1497void KdTree::findNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude) 
     1498{ 
     1499        if (mKdRoot) 
     1500                recFindNodesIn(ray, list, exclude, mKdRoot); 
     1501} 
     1502 
     1503void KdTree::recFindNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 
     1504{ 
     1505        // check intersection 
     1506        if ( !full ) 
     1507        { 
     1508                Intersection isect = intersect(box, node->_getWorldAABB()); 
     1509 
     1510                if ( isect == OUTSIDE ) 
     1511                        return ; 
     1512 
     1513                full = ( isect == INSIDE ); 
     1514        } 
     1515 
     1516        if (node->isLeaf()) 
     1517        { 
     1518                LeafPtr leaf = KDLEAFPTR_CAST(node); 
     1519                for (KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 
     1520                        it != leaf->mKdRenderables.end(); it ++) 
     1521                { 
     1522                        SceneNode *sn = dynamic_cast<SceneNode *>(*it); 
     1523 
     1524                        if (sn != exclude) 
     1525                        { 
     1526                                if (full) 
    9741527                                { 
    975                                         rend = it->getRenderable(); 
    976                                         rend->setClassified(false); 
    977                                         if (rend->attachTo(leaf, this)) 
    978                                         { 
    979                                                 leaf->insert(rend); 
    980                                         } 
    981                                         it++; 
    982                                 } 
    983                                 newNode = leaf; 
    984                                 if (!topNode) 
    985                                         topNode = leaf; 
    986                                 // update stats 
    987                                 ++ mStats.mNumNodes; 
    988                                 ++ mStats.mNumLeaves; 
    989                         } 
    990  
    991                         /************************************************/ 
    992                         /**************** BEGIN CLASSIFY ****************/ 
    993                         /************************************************/ 
    994                         else 
    995                         { 
    996                                 PlaneEventList * eventsLeft = new PlaneEventList(); 
    997                                 PlaneEventList * eventsRight = new PlaneEventList(); 
    998                                 PlaneEventList::iterator begin = sc.events->begin(); 
    999                                 PlaneEventList::iterator end = sc.events->end(); 
    1000                                 PlaneEventList::iterator it = begin; 
    1001                                 // slightly redundant, since we mark each renderable up to 6 times 
    1002                                 while (it != end) 
    1003                                 { 
    1004                                         it->getRenderable()->setSide(PlaneEvent::PES_BOTH); 
    1005                                         it->getRenderable()->setClassified(false); 
    1006                                         it++; 
    1007                                 } 
    1008  
    1009                                 // now classify all renderables. do they belong to the left child, the right child or both? 
    1010                                 it = begin; 
    1011                                 while (it != end) 
    1012                                 { 
    1013                                         it->classify(sc.best->event, sc.best->side); 
    1014                                         it++; 
    1015                                 } 
    1016  
    1017                                 // divide the event lists 
    1018                                 int nLeftS = 0, nRightS = 0, nBothS = 0; 
    1019                                 it = begin; 
    1020                                 while (it != end) 
    1021                                 { 
    1022                                         // right-only events go in the right list 
    1023                                         if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 
    1024                                         { 
    1025                                                 if (!it->getRenderable()->isClassified()) 
    1026                                                 { 
    1027                                                         it->getRenderable()->setClassified(true); 
    1028                                                         nRightS++; 
    1029                                                 } 
    1030  
    1031                                                 eventsRight->push_back(*it); 
    1032                                         } 
    1033                                         // left-only events go in the left list 
    1034                                         else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 
    1035                                         { 
    1036                                                 if (!it->getRenderable()->isClassified()) 
    1037                                                 { 
    1038                                                         it->getRenderable()->setClassified(true); 
    1039                                                         nLeftS++; 
    1040                                                 } 
    1041                                                 eventsLeft->push_back(*it); 
    1042                                         } 
    1043                                         // the rest goes in both lists after being clipped 
    1044                                         else 
    1045                                         { 
    1046                                                 if (!it->getRenderable()->isClassified()) 
    1047                                                 { 
    1048                                                         it->getRenderable()->setClassified(true); 
    1049                                                         nBothS++; 
    1050                                                 } 
    1051  
    1052                                                 eventsRight->push_back(it->clip(sc.best->bright, sc.best->event.getDimension())); 
    1053                                                 eventsLeft->push_back(it->clip(sc.best->bleft, sc.best->event.getDimension())); 
    1054                                         } 
    1055                                         it++; 
    1056                                 } 
    1057  
    1058                                 // create a new branch node 
    1059                                 KdTree::Branch * branch = new KdTree::Branch(this, level, sc.aabb, sc.parent,  
    1060                                         sc.best->event.getSplitPlane(), sc.best->side); 
    1061  
    1062                                 globalTreeCost -= sc.decrease; 
    1063  
    1064  
    1065                                 // now for each potential child node, compute the split plane and the cost decrease 
    1066                                 // and place them in the queue 
    1067                                 if (eventsLeft->size() > 0) 
    1068                                 { 
    1069                                         best = pqFindPlane(eventsLeft, nLeftS + nBothS, sc.best->bleft, globalSA); 
    1070                                         Real old = PlaneEvent::surfaceArea(sc.best->bleft)/globalSA*PlaneEvent::KI*(nLeftS + nBothS); 
    1071                                         SplitCandidate scleft(eventsLeft, nLeftS + nBothS, sc.best->bleft,  
    1072                                                 branch, old, old - best->cost, best, PlaneEvent::PES_LEFT); 
    1073                                         pqueue.push(scleft); 
    1074                                 } 
    1075                                 // cleanup 
    1076                                 else 
    1077                                 { 
    1078                                         delete eventsLeft; 
    1079                                 } 
    1080  
    1081                                 if (eventsRight->size() > 0) 
    1082                                 { 
    1083                                         best = pqFindPlane(eventsRight, nBothS + nRightS, sc.best->bright, globalSA); 
    1084                                         Real old = PlaneEvent::surfaceArea(sc.best->bright)/globalSA*PlaneEvent::KI*(nBothS + nRightS); 
    1085                                         SplitCandidate scright(eventsRight, nBothS + nRightS, sc.best->bright,  
    1086                                                 branch, old, old - best->cost, best, PlaneEvent::PES_RIGHT); 
    1087                                         pqueue.push(scright); 
    1088                                 } 
    1089                                 // cleanup 
    1090                                 else 
    1091                                 { 
    1092                                         delete eventsRight; 
    1093                                 } 
    1094  
    1095                                 newNode = branch; 
    1096                                 if (!topNode) 
    1097                                         topNode = branch; 
    1098  
    1099  
    1100                                 // update stats 
    1101                                 ++ mStats.mNumNodes; 
    1102                         } 
    1103  
    1104                         // attach new node to parent 
    1105                         if (sc.parent) 
    1106                         { 
    1107                                 if (sc.side == PlaneEvent::PES_LEFT) 
    1108                                 { 
    1109                                         sc.parent->mLeft = newNode; 
    1110                                 } 
    1111                                 else if (sc.side == PlaneEvent::PES_RIGHT) 
    1112                                 { 
    1113                                         sc.parent->mRight = newNode; 
     1528                                        list.push_back(sn); 
    11141529                                } 
    11151530                                else 
    11161531                                { 
    1117                                         OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
    1118                                                 "PQBUILD SNAFU - CHILD I AM NOT LEFT NOR RIGHT","KdTree::pqBuild"); 
     1532                                        Intersection nsect = intersect(box, sn->_getWorldAABB()); 
     1533 
     1534                                        if ( nsect != OUTSIDE ) 
     1535                                        { 
     1536                                                list.push_back(sn); 
     1537                                        } 
    11191538                                } 
    11201539                        } 
    1121  
    1122                         // update bounding boxes when geometry (leaf) was added 
    1123                         if (newNode->isLeaf()) 
    1124                                 newNode->_updateBounds(); 
    1125  
    1126                         //cleanup 
    1127                         OGRE_DELETE(sc.events); 
    1128                         OGRE_DELETE(sc.best); 
    1129                 } 
    1130                 mBuildLog->logMessage("Cost after PQBUILD €" + StringConverter::toString(globalTreeCost)); 
    1131                 return topNode; 
    1132         } 
    1133  
    1134         //------------------------------------------------------------------------- 
    1135         SplitInfo * KdTree::pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA) 
    1136         { 
    1137                 static const int dim = 3; 
    1138                 int pStart, pOn, pEnd; 
    1139                 int nLeft[dim], nPlane[dim], nRight[dim]; 
    1140                 for (int i = 0; i < dim; i++) 
    1141                 { 
    1142                         nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 
    1143                 } 
    1144  
    1145                 SplitInfo split, best; 
    1146                 best.cost = Math::POS_INFINITY; 
    1147  
    1148                 Real parentSA = PlaneEvent::surfaceArea(aabb); 
    1149  
    1150                 PlaneEventList::iterator begin = events->begin(); 
    1151                 PlaneEventList::iterator end = events->end(); 
    1152                 PlaneEventList::iterator it = begin; 
    1153                 // try all planes to find the best one for the given set of objects 
     1540                } 
     1541        } 
     1542        else 
     1543        { 
     1544                if (node->getLeftChild()) 
     1545                        recFindNodesIn(box, list, exclude, node->getLeftChild(), full); 
     1546                if (node->getRightChild()) 
     1547                        recFindNodesIn(box, list, exclude, node->getRightChild(), full); 
     1548        } 
     1549} 
     1550 
     1551void KdTree::recFindNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 
     1552{ 
     1553        // TODO 
     1554} 
     1555 
     1556void KdTree::recFindNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 
     1557{ 
     1558        // TODO 
     1559} 
     1560 
     1561void KdTree::recFindNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 
     1562{ 
     1563        // TODO 
     1564} 
     1565 
     1566/************************************************************************/ 
     1567/* KdTree debug & helper functions                                      */ 
     1568/************************************************************************/ 
     1569 
     1570//------------------------------------------------------------------------- 
     1571void KdTree::dump() 
     1572{ 
     1573        //LogManager::getSingleton().logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 
     1574        mBuildLog->logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 
     1575        if (mKdRoot) 
     1576                dump(mKdRoot); 
     1577} 
     1578 
     1579//------------------------------------------------------------------------- 
     1580void KdTree::dump(KdTree::Node * node) 
     1581{ 
     1582        //LogManager * log = LogManager::getSingletonPtr(); 
     1583        KdTreeSceneNode * scenenode; 
     1584        String pad; 
     1585        int p; 
     1586         
     1587        pad = ""; 
     1588        for (p = 0; p < node->getLevel(); p++) 
     1589        { 
     1590                pad += " "; 
     1591        } 
     1592 
     1593        if (node->isLeaf()) 
     1594        { 
     1595                KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
     1596                KdRenderableList::iterator it  = leaf->mKdRenderables.begin(); 
     1597                KdRenderableList::iterator end = leaf->mKdRenderables.end(); 
    11541598                while (it != end) 
    11551599                { 
    1156                         PlaneEventList::iterator p = it; 
    1157                         pStart = pOn = pEnd = 0; 
    1158                         while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 
    1159                         { 
    1160                                 it++; pEnd++; 
    1161                         } 
    1162                         while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 
    1163                         { 
    1164                                 it++; pOn++; 
    1165                         } 
    1166                         while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 
    1167                         { 
    1168                                 it++; pStart++; 
    1169                         } 
    1170                         int d = p->getDimension(); 
    1171                         nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 
    1172                         p->pqSAH(globalSA, parentSA, nLeft[d], nPlane[d], nRight[d], aabb, split); 
    1173                         if (split.cost < best.cost) 
    1174                         { 
    1175                                 best = split; 
    1176                         } 
    1177                         nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 
    1178                 } 
    1179                 return new SplitInfo(best); 
    1180         } 
    1181  
    1182         /************************************************************************/ 
    1183         /* KdTree rendering functions                                           */ 
    1184         /************************************************************************/ 
    1185  
    1186         //------------------------------------------------------------------------- 
    1187         void KdTree::queueVisibleObjects(KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters,  
    1188                 bool showBoxes, KdTree::NodeList& visibleNodes) 
    1189         { 
    1190                 // debug 
    1191                 //cam->mNumVisQueries = 0; 
    1192  
    1193                 if (mKdRoot) 
    1194                         recQueueVisibleObjects(mKdRoot, Root::getSingleton().getCurrentFrameNumber(), 
    1195                                 cam, queue, onlyShadowCasters, showBoxes, visibleNodes); 
    1196  
    1197                 //mBuildLog->logMessage("Frame # " + StringConverter::toString(Root::getSingleton().getCurrentFrameNumber()) + 
    1198                 //      " ," + StringConverter::toString(cam->mNumVisQueries) + " vis queries"); 
    1199         } 
    1200  
    1201         //------------------------------------------------------------------------- 
    1202         void KdTree::recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame,  
    1203                 KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes,  
    1204                 KdTree::NodeList& visibleNodes, bool fullVis) 
    1205         { 
    1206                 KdTreeCamera::NodeVisibility vis = KdTreeCamera::KDNV_PART; 
    1207                 // test visibility 
    1208                 //if (cam->isVisible(node->mAABB)) 
    1209                 if (fullVis ||  
    1210                         ((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 
    1211                         //((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 
    1212                 { 
    1213                         visibleNodes.push_back(node); 
    1214  
    1215                         bool v = (fullVis || vis == KdTreeCamera::KDNV_FULL); 
    1216                         node->queueVisibleObjects(currentFrame, cam, queue, onlyShadowCasters, showBoxes, v); 
    1217  
    1218                         if (!v) 
    1219                         { 
    1220  
    1221                                 if (node->getLeftChild()) 
    1222                                         recQueueVisibleObjects(node->getLeftChild(), currentFrame,  
    1223                                         cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 
    1224                                 if (node->getRightChild()) 
    1225                                         recQueueVisibleObjects(node->getRightChild(), currentFrame,  
    1226                                         cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 
    1227                         } 
    1228                 } 
    1229         } 
    1230  
    1231         //------------------------------------------------------------------------- 
    1232         void KdTree::setEnhancedVis(bool enh) 
    1233         { 
    1234                 if (enh) 
    1235                         getVisibility = &KdTreeCamera::getVisibilityEnhanced; 
    1236                 else 
    1237                         getVisibility = &KdTreeCamera::getVisibilitySimple; 
    1238         } 
    1239  
    1240         //------------------------------------------------------------------------- 
    1241         bool KdTree::getEnhancedVis() 
    1242         { 
    1243                 return getVisibility == &KdTreeCamera::getVisibilityEnhanced; 
    1244         } 
    1245  
    1246         //------------------------------------------------------------------------- 
    1247         //void KdTree::findVisibleNodes(NodeList& visibleNodes, Camera * cam) 
    1248         //{ 
    1249         //      if (mKdRoot) 
    1250         //              recFindVisibleNodes(mKdRoot, visibleNodes, cam); 
    1251         //} 
    1252  
    1253         ////------------------------------------------------------------------------- 
    1254         //void KdTree::recFindVisibleNodes(KdTree::Node * node, NodeList& visibleNodes, Camera * cam) 
    1255         //{ 
    1256         //      // test visibility 
    1257         //      if (cam->isVisible(node->mAABB)) 
    1258         //      { 
    1259         //              visibleNodes.push_back(node); 
    1260  
    1261         //              if (node->getLeftChild()) 
    1262         //                      recFindVisibleNodes(node->getLeftChild(), visibleNodes, cam); 
    1263         //              if (node->getRightChild()) 
    1264         //                      recFindVisibleNodes(node->getRightChild(), visibleNodes, cam); 
    1265         //      } 
    1266         //} 
    1267  
    1268         /************************************************************************/ 
    1269         /* KdTree debug & helper functions                                      */ 
    1270         /************************************************************************/ 
    1271  
    1272         //------------------------------------------------------------------------- 
    1273         void KdTree::dump() 
    1274         { 
    1275                 //LogManager::getSingleton().logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 
    1276                 mBuildLog->logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 
    1277                 if (mKdRoot) 
    1278                         dump(mKdRoot); 
    1279         } 
    1280  
    1281         //------------------------------------------------------------------------- 
    1282         void KdTree::dump(KdTree::Node * node) 
    1283         { 
    1284                 //LogManager * log = LogManager::getSingletonPtr(); 
    1285                 KdTreeSceneNode * scenenode; 
    1286                 String pad; 
    1287                 int p; 
    1288                  
    1289                 pad = ""; 
    1290                 for (p = 0; p < node->getLevel(); p++) 
    1291                 { 
    1292                         pad += " "; 
    1293                 } 
    1294  
    1295                 if (node->isLeaf()) 
    1296                 { 
    1297                         KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
    1298                         KdRenderableList::iterator it  = leaf->mKdRenderables.begin(); 
    1299                         KdRenderableList::iterator end = leaf->mKdRenderables.end(); 
    1300                         while (it != end) 
    1301                         { 
    1302                                 scenenode = dynamic_cast<KdTreeSceneNode *>(*it); 
    1303                                 mBuildLog->logMessage(pad + "# Leaf   level " +  
    1304                                         StringConverter::toString(node->getLevel()) +  
    1305                                         " SceneNode " + scenenode->getName()); 
    1306                                 mBuildLog->logMessage(pad + "## Objects: " + scenenode->dumpToString()); 
    1307                                 it++; 
    1308                         } 
    1309                 } 
    1310                 else 
    1311                 { 
    1312                         KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
    1313                         if (branch->mLeft) 
    1314                         { 
    1315                                 mBuildLog->logMessage(pad + "# Branch level " +  
    1316                                         StringConverter::toString(node->getLevel()) + " Left Child"); 
    1317                                 dump(branch->mLeft); 
    1318                         } 
    1319                         if (branch->mRight) 
    1320                         { 
    1321                                 mBuildLog->logMessage(pad + "# Branch level " +  
    1322                                         StringConverter::toString(node->getLevel()) + " Right Child"); 
    1323                                 dump(branch->mRight); 
    1324                         } 
    1325                 } 
    1326         } 
    1327  
    1328         //------------------------------------------------------------------------- 
    1329         Real KdTree::calcCost() 
    1330         { 
    1331                 if (mKdRoot) 
    1332                         return calcCost(mKdRoot, PlaneEvent::surfaceArea(mKdRoot->mAABB)); 
    1333                 else 
    1334                         return 0; 
    1335         } 
    1336  
    1337         //------------------------------------------------------------------------- 
    1338         Real KdTree::calcCost(KdTree::Node * node, Real vs) 
    1339         { 
    1340                 if (node == 0) 
    1341                         return 0.0; 
    1342  
    1343                 if (node->isLeaf()) 
    1344                 { 
    1345                         KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
    1346                         return (PlaneEvent::surfaceArea(node->mAABB)/vs) * 
    1347                                 PlaneEvent::KI * leaf->mKdRenderables.size(); 
    1348                 } 
    1349                 else 
    1350                 { 
    1351                         KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
    1352                         return (PlaneEvent::surfaceArea(node->mAABB)/vs) * PlaneEvent::KT +  
    1353                                 calcCost(branch->mLeft, vs) + calcCost(branch->mRight, vs); 
    1354                 } 
    1355         } 
    1356  
    1357         /************************************************************************/ 
    1358         /* KdTree::Node/Branch/Leaf functions                                   */ 
    1359         /************************************************************************/ 
    1360  
    1361         //------------------------------------------------------------------------- 
    1362         KdTree::Leaf::~Leaf() 
    1363         { 
    1364                 // detach all scene nodes in the case that we are rebuilding 
    1365                 // the tree but not the scene 
    1366                 KdRenderableList::iterator it = mKdRenderables.begin(); 
    1367                 KdRenderableList::iterator end = mKdRenderables.end(); 
    1368                 while (it != end) 
    1369                 { 
    1370                         (*it)->detachFrom(this); 
     1600                        scenenode = dynamic_cast<KdTreeSceneNode *>(*it); 
     1601                        mBuildLog->logMessage(pad + "# Leaf   level " +  
     1602                                StringConverter::toString(node->getLevel()) +  
     1603                                " SceneNode " + scenenode->getName()); 
     1604                        mBuildLog->logMessage(pad + "## Objects: " + scenenode->dumpToString()); 
    13711605                        it++; 
    13721606                } 
    1373                 mKdRenderables.clear(); 
    1374         } 
    1375  
    1376         //------------------------------------------------------------------------- 
    1377         void KdTree::Leaf::queueVisibleObjects(unsigned long currentFrame,  
    1378                 Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, bool fullVis) 
    1379         { 
    1380                 KdRenderableList::iterator it  = mKdRenderables.begin(); 
    1381                 KdRenderableList::iterator end = mKdRenderables.end(); 
    1382                 while (it != end) 
    1383                 {                        
    1384                         if (!(*it)->isQueued(currentFrame, cam)) 
    1385                         { 
    1386                                 (*it)->queueObjects(cam, queue, onlyShadowCasters); 
    1387                         } 
    1388                         it++; 
    1389                 } 
    1390  
    1391                 if (showBoxes) 
    1392                         if (mLevel == mOwner->getHiLiteLevel() || mOwner->getShowAllBoxes()) 
    1393                                 queue->addRenderable(getWireBoundingBox()); 
    1394         } 
    1395  
    1396         //------------------------------------------------------------------------- 
    1397         void KdTree::Leaf::getGeometryList(GtpVisibility::GeometryVector *geometryList) 
    1398         { 
    1399                 KdRenderableList::iterator it = mKdRenderables.begin(); 
    1400                 KdRenderableList::iterator end = mKdRenderables.end(); 
    1401                 while (it != end) 
    1402                 { 
    1403                         (*it)->getGeometryList(geometryList); 
    1404                         it++; 
    1405                 } 
    1406         } 
    1407  
    1408         //------------------------------------------------------------------------- 
    1409         // update the world aabb based on the contained geometry 
    1410         void KdTree::Leaf::_updateBounds(bool recurse) 
    1411         { 
    1412                 // reset box 
    1413                 mWorldAABB.setNull(); 
    1414  
    1415                 // merge boxes from attached geometry 
    1416                 KdRenderableList::iterator it = mKdRenderables.begin(); 
    1417                 KdRenderableList::iterator end = mKdRenderables.end(); 
    1418                 while (it != end) 
    1419                 { 
    1420                         //(*it)->_updateBounds(); 
    1421                         mWorldAABB.merge((*it)->getBoundingBox()); 
    1422                         it++; 
    1423                 } 
    1424  
    1425                 // update parent recursively 
    1426                 if (recurse && mParent) 
    1427                         mParent->_updateBounds(recurse); 
    1428         } 
     1607        } 
     1608        else 
     1609        { 
     1610                KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
     1611                if (branch->mLeft) 
     1612                { 
     1613                        mBuildLog->logMessage(pad + "# Branch level " +  
     1614                                StringConverter::toString(node->getLevel()) + " Left Child"); 
     1615                        dump(branch->mLeft); 
     1616                } 
     1617                if (branch->mRight) 
     1618                { 
     1619                        mBuildLog->logMessage(pad + "# Branch level " +  
     1620                                StringConverter::toString(node->getLevel()) + " Right Child"); 
     1621                        dump(branch->mRight); 
     1622                } 
     1623        } 
     1624} 
     1625 
     1626//------------------------------------------------------------------------- 
     1627Real KdTree::calcCost() 
     1628{ 
     1629        if (mKdRoot) 
     1630                return calcCost(mKdRoot, PlaneEvent::surfaceArea(mKdRoot->mAABB)); 
     1631        else 
     1632                return 0; 
     1633} 
     1634 
     1635//------------------------------------------------------------------------- 
     1636Real KdTree::calcCost(KdTree::Node * node, Real vs) 
     1637{ 
     1638        if (node == 0) 
     1639                return 0.0; 
     1640 
     1641        if (node->isLeaf()) 
     1642        { 
     1643                KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 
     1644                return (PlaneEvent::surfaceArea(node->mAABB)/vs) * 
     1645                        PlaneEvent::KI * leaf->mKdRenderables.size(); 
     1646        } 
     1647        else 
     1648        { 
     1649                KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 
     1650                return (PlaneEvent::surfaceArea(node->mAABB)/vs) * PlaneEvent::KT +  
     1651                        calcCost(branch->mLeft, vs) + calcCost(branch->mRight, vs); 
     1652        } 
     1653} 
     1654 
     1655/************************************************************************/ 
     1656/* KdTree::Node/Branch/Leaf functions                                   */ 
     1657/************************************************************************/ 
     1658 
     1659//------------------------------------------------------------------------- 
     1660KdTree::Leaf::~Leaf() 
     1661{ 
     1662        // detach all scene nodes in the case that we are rebuilding 
     1663        // the tree but not the scene 
     1664        KdRenderableList::iterator it = mKdRenderables.begin(); 
     1665        KdRenderableList::iterator end = mKdRenderables.end(); 
     1666        while (it != end) 
     1667        { 
     1668                (*it)->detachFrom(this); 
     1669                it++; 
     1670        } 
     1671        mKdRenderables.clear(); 
     1672} 
     1673 
     1674//------------------------------------------------------------------------- 
     1675void KdTree::Leaf::queueVisibleObjects(unsigned long currentFrame,  
     1676        Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, bool fullVis) 
     1677{ 
     1678        KdRenderableList::iterator it  = mKdRenderables.begin(); 
     1679        KdRenderableList::iterator end = mKdRenderables.end(); 
     1680        while (it != end) 
     1681        {                        
     1682                if (!(*it)->isQueued(currentFrame, cam)) 
     1683                { 
     1684                        (*it)->queueObjects(cam, queue, onlyShadowCasters); 
     1685                } 
     1686                it++; 
     1687        } 
     1688 
     1689        if (showBoxes) 
     1690                if (mLevel == mOwner->getHiLiteLevel() || mOwner->getShowAllBoxes()) 
     1691                        queue->addRenderable(getWireBoundingBox()); 
     1692} 
     1693 
     1694//------------------------------------------------------------------------- 
     1695void KdTree::Leaf::getGeometryList(GtpVisibility::GeometryVector *geometryList) 
     1696{ 
     1697        KdRenderableList::iterator it = mKdRenderables.begin(); 
     1698        KdRenderableList::iterator end = mKdRenderables.end(); 
     1699        while (it != end) 
     1700        { 
     1701                (*it)->getGeometryList(geometryList); 
     1702                it++; 
     1703        } 
     1704} 
     1705 
     1706//------------------------------------------------------------------------- 
     1707// update the world aabb based on the contained geometry 
     1708void KdTree::Leaf::_updateBounds(bool recurse) 
     1709{ 
     1710        // reset box 
     1711        mWorldAABB.setNull(); 
     1712 
     1713        // merge boxes from attached geometry 
     1714        KdRenderableList::iterator it = mKdRenderables.begin(); 
     1715        KdRenderableList::iterator end = mKdRenderables.end(); 
     1716        while (it != end) 
     1717        { 
     1718                //(*it)->_updateBounds(); 
     1719                mWorldAABB.merge((*it)->getBoundingBox()); 
     1720                it++; 
     1721        } 
     1722 
     1723        // update parent recursively 
     1724        if (recurse && mParent) 
     1725                mParent->_updateBounds(recurse); 
     1726} 
     1727 
    14291728} // namespace Ogre 
Note: See TracChangeset for help on using the changeset viewer.