"L. Spiro Engine"
|
00001 00017 #ifndef __LSP_SOLIDLEAFBSPBASE_H__ 00018 #define __LSP_SOLIDLEAFBSPBASE_H__ 00019 00020 #include "../LSPPhysicsLib.h" 00021 #include "../Intersections/LSPClassify.h" 00022 #include "../Intersections/LSPIntersect.h" 00023 #include "../Misc/LSPPhysUtils.h" 00024 #include "Vector/LSTLVector.h" 00025 00026 #ifdef LSP_TOOL 00027 #include <iostream> 00028 #endif // #ifdef LSP_TOOL 00029 00030 namespace lsp { 00031 00039 template <typename _tType, typename _tVecType, typename _tPlaneType, typename _tPolyType> 00040 class CSolidLeafBspBase { 00041 public : 00042 // == Various constructors. 00043 LSE_CALLCTOR CSolidLeafBspBase() { 00044 } 00045 00046 00047 // == Types. 00051 typedef struct LSP_NODE { 00055 LSP_NODE * pnParent; 00056 00060 LSP_NODE * pnFront; 00061 00065 LSP_NODE * pnBack; 00066 00070 CVector<_tPolyType, LSUINT32, 4096UL> 00071 vPolies; 00072 00076 _tPlaneType tPlane; 00077 00081 LSUINTPTR uiptrUser; 00082 00083 00084 // == Various constructors. 00085 LSE_CALLCTOR LSP_NODE() : 00086 pnParent( NULL ), 00087 pnFront( NULL ), 00088 pnBack( NULL ), 00089 uiptrUser( 0UL ) { 00090 } 00091 LSE_CALLCTOR ~LSP_NODE() { 00092 if ( pnFront ) { 00093 pnFront->~LSP_NODE(); 00094 pnFront = NULL; 00095 } 00096 if ( pnBack ) { 00097 pnBack->~LSP_NODE(); 00098 pnBack = NULL; 00099 } 00100 } 00101 } * LPLSP_NODE, * const LPCLSP_NODE; 00102 00103 00104 // == Functions. 00110 const LSP_NODE * LSE_CALL Root() const { 00111 return &m_nRoot; 00112 } 00113 00123 LSBOOL LSE_CALL CreateBsp( const _tPolyType * _ppPolies, LSUINT32 _ui32Total, 00124 CStackAllocator * _psaAllocator, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00125 // Make a copy of the polygons. 00126 CVector<_tPolyType, LSUINT32, 4096UL> vPolyCopy; 00127 vPolyCopy.Allocate( _ui32Total ); 00128 for ( LSUINT32 I = 0UL; I < _ui32Total; ++I ) { 00129 if ( _ppPolies[I].TotalSegments() ) { 00130 if ( !vPolyCopy.Push( _tPolyType() ) ) { return false; } 00131 if ( !vPolyCopy[vPolyCopy.Length()-1UL].Copy( _ppPolies[I], _psaAllocator ) ) { return false; } 00132 } 00133 } 00134 vPolyCopy.Snap(); 00135 00136 return CreateBsp( m_nRoot, vPolyCopy, _psaAllocator, _fThickness ); 00137 } 00138 00149 LSBOOL LSE_CALL CreateBspConvex( const _tPolyType * _ppPolies, LSUINT32 _ui32Total, 00150 CStackAllocator * _psaAllocator, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00151 // Make a copy of the polygons. 00152 CVector<_tPolyType, LSUINT32, 4096UL> vPolyCopy; 00153 vPolyCopy.Allocate( _ui32Total ); 00154 for ( LSUINT32 I = 0UL; I < _ui32Total; ++I ) { 00155 if ( _ppPolies[I].TotalSegments() ) { 00156 if ( !vPolyCopy.Push( _tPolyType() ) ) { return false; } 00157 if ( !vPolyCopy[vPolyCopy.Length()-1UL].Copy( _ppPolies[I], _psaAllocator ) ) { return false; } 00158 } 00159 } 00160 vPolyCopy.Snap(); 00161 00162 return CreateBspConvex( m_nRoot, vPolyCopy, _psaAllocator, _fThickness ); 00163 } 00164 00171 LSBOOL LSE_CALL GetLeafs( CVectorPoD<LSP_NODE *, LSUINT32> &_vArray ) { 00172 return GetLeafs( &m_nRoot, _vArray ); 00173 } 00174 00182 LSBOOL LSE_CALL GetLeafs( CVectorPoD<const LSP_NODE *, LSUINT32> &_vArray, CVectorPoD<const LSP_NODE *, LSUINT32> &_vStack ) const { 00183 return GetLeafs( &m_nRoot, _vArray, _vStack ); 00184 } 00185 00193 LSBOOL LSE_CALL GetLeafs( LSP_NODE * _pnNode, CVectorPoD<LSP_NODE *, LSUINT32> &_vArray ) const { 00194 // Explicit stacking for stability. 00195 CVector<LSP_NODE *, LSUINT32, 4096UL> vStack; 00196 if ( !vStack.Push( _pnNode ) ) { return false; } 00197 while ( vStack.Length() ) { 00198 LSP_NODE * pnThis = vStack[vStack.Length()-1UL]; 00199 vStack.PopNoDealloc(); 00200 if ( !_vArray.Push( pnThis ) ) { return false; } 00201 00202 if ( pnThis->pnFront ) { 00203 if ( !vStack.Push( pnThis->pnFront ) ) { return false; } 00204 } 00205 if ( pnThis->pnBack ) { 00206 if ( !vStack.Push( pnThis->pnBack ) ) { return false; } 00207 } 00208 } 00209 return true; 00210 } 00211 00220 LSBOOL LSE_CALL GetLeafs( const LSP_NODE * _pnNode, CVectorPoD<const LSP_NODE *, LSUINT32> &_vArray, 00221 CVectorPoD<const LSP_NODE *, LSUINT32> &_vStack ) const { 00222 // Explicit stacking for stability. 00223 _vStack.ResetNoDealloc(); 00224 if ( !_vStack.Push( _pnNode ) ) { return false; } 00225 while ( _vStack.Length() ) { 00226 const LSP_NODE * pnThis = _vStack[_vStack.Length()-1UL]; 00227 _vStack.PopNoDealloc(); 00228 if ( !_vArray.Push( pnThis ) ) { return false; } 00229 00230 if ( pnThis->pnFront ) { 00231 if ( !_vStack.Push( pnThis->pnFront ) ) { return false; } 00232 } 00233 if ( pnThis->pnBack ) { 00234 if ( !_vStack.Push( pnThis->pnBack ) ) { return false; } 00235 } 00236 } 00237 return true; 00238 } 00239 00247 static LSBOOL LSE_CALL GetParents( const LSP_NODE * _pnNode, CVectorPoD<LSP_NODE *, LSUINT32> &_vArray ) { 00248 _vArray.ResetNoDealloc(); 00249 for ( LSP_NODE * pnParent = _pnNode->pnParent; pnParent; pnParent = pnParent->pnParent ) { 00250 if ( !_vArray.Push( pnParent ) ) { return false; } 00251 } 00252 return true; 00253 } 00254 00255 00256 protected : 00257 // == Types. 00261 typedef struct LSP_STACK { 00265 LSP_NODE * pnNode; 00266 00270 CVector<_tPolyType, LSUINT32, 4096UL> 00271 vPolies; 00272 } * LPLSP_STACK, * const LPCLSP_STACK; 00273 00274 00275 // == Members. 00279 LSP_NODE m_nRoot; 00280 00281 00282 // == Functions 00292 LSBOOL LSE_CALL CreateBsp( LSP_NODE &_nNode, const CVector<_tPolyType, LSUINT32, 4096UL> &_vPolies, 00293 CStackAllocator * _psaAllocator, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00294 // Explicit stacking is used for stability. Stack overflow on large/complicated next-generation maps is not 00295 // a problem for this algorithm. 00296 CVector<LSP_STACK, LSUINT32, 4096UL> vStack; 00297 vStack.Allocate( _vPolies.Length() ); // The number of polygons should be sufficient stack size. 00298 00299 // Start it off with the first node. 00300 if ( !vStack.Push( LSP_STACK() ) ) { return false; } 00301 vStack[0].pnNode = &_nNode; 00302 vStack[0].vPolies = _vPolies; 00303 00304 CVector<_tPolyType, LSUINT32, 4096UL> vFrontPolies, vBackPolies; 00305 00306 while ( vStack.Length() ) { 00307 LSP_STACK sThis = vStack[vStack.Length()-1UL]; 00308 vStack.PopNoDealloc(); 00309 if ( sThis.vPolies.Length() == 0UL ) { continue; } 00310 vFrontPolies.ResetNoDealloc(); 00311 vBackPolies.ResetNoDealloc(); 00312 LSUINT32 ui32Index; 00313 sThis.pnNode->tPlane = BestSplittingPlane( sThis.vPolies, ui32Index, _fThickness ); 00314 #ifdef LSP_TOOL 00315 ::printf( "." ); 00316 #endif // #ifdef LSP_TOOL 00317 00318 for ( LSUINT32 I = 0UL; I < sThis.vPolies.Length(); ++I ) { 00319 if ( I == ui32Index ) { 00320 if ( !sThis.pnNode->vPolies.Push( sThis.vPolies[I] ) ) { 00321 return false; 00322 } 00323 continue; 00324 } 00325 switch ( CClassify::Polygon( sThis.vPolies[I], sThis.pnNode->tPlane, _fThickness ) ) { 00326 case LSM_PI_FRONT : { 00327 if ( !vFrontPolies.Push( sThis.vPolies[I] ) ) { return false; } 00328 break; 00329 } 00330 case LSM_PI_BACK : { 00331 if ( !vBackPolies.Push( sThis.vPolies[I] ) ) { return false; } 00332 break; 00333 } 00334 case LSM_PI_COPLANAR : { 00335 if ( !sThis.pnNode->vPolies.Push( sThis.vPolies[I] ) ) { 00336 return false; 00337 } 00338 break; 00339 } 00340 case LSM_PI_INTERSECT : { 00341 LSUINT32 ui32Left, ui32Right; 00342 CPhysUtils::Split<_tType, _tVecType, _tPolyType, _tPlaneType>( sThis.vPolies[I], sThis.pnNode->tPlane, &ui32Left, NULL, &ui32Right, NULL, 00343 _fThickness ); 00344 _tPolyType tLeft, tRight; 00345 if ( !tLeft.SetTotalSides( ui32Left, _psaAllocator ) ) { 00346 return false; 00347 } 00348 if ( !tRight.SetTotalSides( ui32Right, _psaAllocator ) ) { 00349 return false; 00350 } 00351 CPhysUtils::Split<_tType, _tVecType, _tPolyType, _tPlaneType>( sThis.vPolies[I], sThis.pnNode->tPlane, NULL, &tLeft, NULL, &tRight, 00352 _fThickness ); 00353 if ( !vFrontPolies.Push( tLeft ) ) { return false; } 00354 if ( !vBackPolies.Push( tRight ) ) { return false; } 00355 break; 00356 } 00357 } 00358 } 00359 00360 sThis.pnNode->vPolies.Snap(); 00361 if ( vFrontPolies.Length() ) { 00362 sThis.pnNode->pnFront = static_cast<LSP_NODE *>(_psaAllocator->Alloc( sizeof( LSP_NODE ), 4UL )); 00363 if ( !sThis.pnNode->pnFront ) { 00364 return false; 00365 } 00366 new( sThis.pnNode->pnFront ) LSP_NODE(); 00367 if ( !vStack.Push( LSP_STACK() ) ) { 00368 return false; 00369 } 00370 sThis.pnNode->pnFront->pnParent = sThis.pnNode; 00371 vStack[vStack.Length()-1].pnNode = sThis.pnNode->pnFront; 00372 vStack[vStack.Length()-1].vPolies = vFrontPolies; 00373 } 00374 if ( vBackPolies.Length() ) { 00375 sThis.pnNode->pnBack = static_cast<LSP_NODE *>(_psaAllocator->Alloc( sizeof( LSP_NODE ), 4UL )); 00376 if ( !sThis.pnNode->pnBack ) { 00377 return false; 00378 } 00379 new( sThis.pnNode->pnBack ) LSP_NODE(); 00380 if ( !vStack.Push( LSP_STACK() ) ) { 00381 return false; 00382 } 00383 sThis.pnNode->pnBack->pnParent = sThis.pnNode; 00384 vStack[vStack.Length()-1].pnNode = sThis.pnNode->pnBack; 00385 vStack[vStack.Length()-1].vPolies = vBackPolies; 00386 } 00387 } 00388 00389 return true; 00390 } 00391 00401 LSBOOL LSE_CALL CreateBspConvex( LSP_NODE &_nNode, const CVector<_tPolyType, LSUINT32, 4096UL> &_vPolies, 00402 CStackAllocator * _psaAllocator, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00403 // Explicit stacking is used for stability. Stack overflow on large/complicated next-generation maps is not 00404 // a problem for this algorithm. 00405 CVector<LSP_STACK, LSUINT32, 4096UL> vStack; 00406 vStack.Allocate( _vPolies.Length() ); // The number of polygons should be sufficient stack size. 00407 00408 // Start it off with the first node. 00409 if ( !vStack.Push( LSP_STACK() ) ) { return false; } 00410 vStack[0].pnNode = &_nNode; 00411 vStack[0].vPolies = _vPolies; 00412 00413 CVector<_tPolyType, LSUINT32, 4096UL> vFrontPolies, vBackPolies; 00414 #ifdef LSP_TOOL 00415 LSUINT32 ui32Max = 0UL; 00416 #endif // #ifdef LSP_TOOL 00417 while ( vStack.Length() ) { 00418 LSP_STACK sThis = vStack[vStack.Length()-1UL]; 00419 vStack.PopNoDealloc(); 00420 if ( sThis.vPolies.Length() == 0UL ) { continue; } 00421 if ( sThis.vPolies.Length() == 1UL ) { 00422 // Only one polygon. This is a leaf. 00423 sThis.pnNode->tPlane = sThis.vPolies[0].Plane(); 00424 if ( !sThis.pnNode->vPolies.Push( sThis.vPolies[0] ) ) { 00425 return false; 00426 } 00427 sThis.pnNode->vPolies.Snap(); 00428 continue; 00429 } 00430 vFrontPolies.ResetNoDealloc(); 00431 vBackPolies.ResetNoDealloc(); 00432 LSUINT32 ui32Index; 00433 sThis.pnNode->tPlane = BestSplittingPlane( sThis.vPolies, ui32Index, _fThickness ); 00434 #ifdef LSP_TOOL 00435 ::printf( "." ); 00436 #endif // #ifdef LSP_TOOL 00437 00438 for ( LSUINT32 I = 0UL; I < sThis.vPolies.Length(); ++I ) { 00439 if ( I == ui32Index ) { 00440 //if ( !sThis.pnNode->vPolies.Push( sThis.vPolies[I] ) ) { 00441 sThis.vPolies[I].SetAsSplitter( true ); 00442 if ( !vFrontPolies.Push( sThis.vPolies[I] ) ) { 00443 return false; 00444 } 00445 continue; 00446 } 00447 switch ( CClassify::Polygon( sThis.vPolies[I], sThis.pnNode->tPlane, _fThickness ) ) { 00448 case LSM_PI_FRONT : { 00449 if ( !vFrontPolies.Push( sThis.vPolies[I] ) ) { return false; } 00450 break; 00451 } 00452 case LSM_PI_BACK : { 00453 sThis.vPolies[I].SetAsSplitter( false ); 00454 if ( !vBackPolies.Push( sThis.vPolies[I] ) ) { return false; } 00455 break; 00456 } 00457 case LSM_PI_COPLANAR : { 00458 if ( sThis.vPolies[I].Plane().n * sThis.pnNode->tPlane.n > _tType( 0 ) ) { 00459 //if ( !sThis.pnNode->vPolies.Push( sThis.vPolies[I] ) ) { 00460 sThis.vPolies[I].SetAsSplitter( true ); 00461 if ( !vFrontPolies.Push( sThis.vPolies[I] ) ) { 00462 return false; 00463 } 00464 } 00465 else { 00466 sThis.vPolies[I].SetAsSplitter( false ); 00467 if ( !vBackPolies.Push( sThis.vPolies[I] ) ) { 00468 return false; 00469 } 00470 } 00471 00472 break; 00473 } 00474 case LSM_PI_INTERSECT : { 00475 LSUINT32 ui32Left, ui32Right; 00476 CPhysUtils::Split<_tType, _tVecType, _tPolyType, _tPlaneType>( sThis.vPolies[I], sThis.pnNode->tPlane, &ui32Left, NULL, &ui32Right, NULL, 00477 _fThickness ); 00478 _tPolyType tLeft, tRight; 00479 if ( !tLeft.SetTotalSides( ui32Left, _psaAllocator ) ) { 00480 return false; 00481 } 00482 if ( !tRight.SetTotalSides( ui32Right, _psaAllocator ) ) { 00483 return false; 00484 } 00485 CPhysUtils::Split<_tType, _tVecType, _tPolyType, _tPlaneType>( sThis.vPolies[I], sThis.pnNode->tPlane, NULL, &tLeft, NULL, &tRight, 00486 _fThickness ); 00487 if ( sThis.vPolies[I].IsSplitter() ) { 00488 tLeft.SetAsSplitter( true ); 00489 //tRight.SetAsSplitter( true ); 00490 } 00491 if ( !vFrontPolies.Push( tLeft ) ) { return false; } 00492 if ( !vBackPolies.Push( tRight ) ) { return false; } 00493 break; 00494 } 00495 } 00496 } 00497 if ( vFrontPolies.Length() && (AllAreSplitters( vFrontPolies ) || AllAreConvex( sThis.pnNode->vPolies, vFrontPolies, _fThickness )) ) { 00498 // Add them to the front node. 00499 if ( !sThis.pnNode->vPolies.Append( &vFrontPolies[0], vFrontPolies.Length() ) ) { 00500 return false; 00501 } 00502 00503 /*sThis.pnNode->pnFront = static_cast<LSP_NODE *>(_psaAllocator->Alloc( sizeof( LSP_NODE ), 4UL )); 00504 if ( !sThis.pnNode->pnFront ) { 00505 return false; 00506 } 00507 new( sThis.pnNode->pnFront ) LSP_NODE(); 00508 sThis.pnNode->pnFront->pnParent = sThis.pnNode; 00509 if ( !sThis.pnNode->pnFront->vPolies.Append( &vFrontPolies[0], vFrontPolies.Length() ) ) { 00510 sThis.pnNode->pnFront->vPolies.Append( &vFrontPolies[0], vFrontPolies.Length() ); 00511 return false; 00512 } 00513 sThis.pnNode->pnFront->vPolies.Snap();*/ 00514 00515 #ifdef LSP_TOOL 00516 ::printf( "%u ", sThis.pnNode->vPolies.Length() ); 00517 ui32Max = CStd::Max( ui32Max, sThis.pnNode->vPolies.Length() ); 00518 /*::printf( "%u ", sThis.pnNode->pnFront->vPolies.Length() ); 00519 ui32Max = CStd::Max( ui32Max, sThis.pnNode->pnFront->vPolies.Length() );*/ 00520 #endif // #ifdef LSP_TOOL 00521 vFrontPolies.ResetNoDealloc(); 00522 } 00523 00524 sThis.pnNode->vPolies.Snap(); 00525 if ( vFrontPolies.Length() ) { 00526 sThis.pnNode->pnFront = static_cast<LSP_NODE *>(_psaAllocator->Alloc( sizeof( LSP_NODE ), 4UL )); 00527 if ( !sThis.pnNode->pnFront ) { 00528 return false; 00529 } 00530 new( sThis.pnNode->pnFront ) LSP_NODE(); 00531 if ( !vStack.Push( LSP_STACK() ) ) { 00532 return false; 00533 } 00534 sThis.pnNode->pnFront->pnParent = sThis.pnNode; 00535 vStack[vStack.Length()-1].pnNode = sThis.pnNode->pnFront; 00536 vStack[vStack.Length()-1].vPolies = vFrontPolies; 00537 } 00538 if ( vBackPolies.Length() ) { 00539 sThis.pnNode->pnBack = static_cast<LSP_NODE *>(_psaAllocator->Alloc( sizeof( LSP_NODE ), 4UL )); 00540 if ( !sThis.pnNode->pnBack ) { 00541 return false; 00542 } 00543 new( sThis.pnNode->pnBack ) LSP_NODE(); 00544 if ( !vStack.Push( LSP_STACK() ) ) { 00545 return false; 00546 } 00547 sThis.pnNode->pnBack->pnParent = sThis.pnNode; 00548 vStack[vStack.Length()-1].pnNode = sThis.pnNode->pnBack; 00549 vStack[vStack.Length()-1].vPolies = vBackPolies; 00550 } 00551 } 00552 #ifdef LSP_TOOL 00553 ::printf( "\r\nMax: %u.\r\n", ui32Max ); 00554 #endif // #ifdef LSP_TOOL 00555 return true; 00556 } 00557 00566 _tPlaneType LSE_CALL BestSplittingPlane( const CVector<_tPolyType, LSUINT32, 4096UL> &_vPolies, LSUINT32 &_ui32Index, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00567 // Blend factor for optimizing for balancing splits (to be tweaked). 00568 _tType fK = static_cast<_tType>(0.95); 00569 00570 // Variables for tracking the best plane seen so far. 00571 _tPlaneType pBest; 00572 _tType fBestScore = static_cast<_tType>(LSM_INFINITY); // Lower score = better. 00573 LSBOOL bFoundOneBest = false; 00574 00575 // Compare every plane against every other plane. 00576 for ( LSUINT32 I = 0UL; I < _vPolies.Length(); ++I ) { 00577 if ( _vPolies[I].IsSplitter() ) { continue; } 00578 LSUINT32 ui32Front = 0, ui32Behind = 0, ui32Straddling = 0; 00579 const _tPlaneType & pPlane = _vPolies[I].Plane(); 00580 if ( bFoundOneBest && pBest == pPlane ) { continue; } 00581 00582 // Check against all other polygons. See how many are in front, 00583 // behind, or straddling. 00584 for ( LSUINT32 J = 0UL; J < _vPolies.Length(); ++J ) { 00585 if ( I == J ) { continue; } 00586 00587 switch ( CClassify::Polygon( _vPolies[J], pPlane, _fThickness ) ) { 00588 case LSM_PI_COPLANAR : { 00589 // Send these down the front by falling through. 00590 } 00591 case LSM_PI_FRONT : { 00592 ++ui32Front; 00593 break; 00594 } 00595 case LSM_PI_BACK : { 00596 ++ui32Behind; 00597 break; 00598 } 00599 case LSM_PI_INTERSECT : { 00600 ++ui32Straddling; 00601 break; 00602 } 00603 } 00604 } 00605 00606 // Get the score for this plane. 00607 _tType fScore = fK * ui32Straddling + (static_cast<_tType>(1.0) - fK) * CMathLib::AbsT<_tType>( static_cast<_tType>(ui32Front - ui32Behind) ); 00608 if ( fScore < fBestScore ) { 00609 fBestScore = fScore; 00610 pBest = pPlane; 00611 bFoundOneBest = true; 00612 _ui32Index = I; 00613 } 00614 } 00615 if ( !bFoundOneBest ) { 00616 // Just find one that is not a splitter. 00617 for ( LSUINT32 I = 0UL; I < _vPolies.Length(); ++I ) { 00618 if ( !_vPolies[I].IsSplitter() ) { 00619 pBest = _vPolies[I].Plane(); 00620 _ui32Index = I; 00621 break; 00622 } 00623 } 00624 } 00625 return pBest; 00626 } 00627 00636 LSBOOL LSE_CALL AllAreConvex( const CVector<_tPolyType, LSUINT32, 4096UL> &_vPlanePolies, const CVector<_tPolyType, LSUINT32, 4096UL> &_vPolies, _tType _fThickness = static_cast<_tType>(LSM_PLANE_THICKNESS) ) { 00637 for ( LSUINT32 I = 0UL; I < _vPolies.Length(); ++I ) { 00638 // If any other polygons are behind this one's plane, it is not convex. 00639 // Check here first since it is more likely to exit early. 00640 for ( LSUINT32 J = I + 1UL; J < _vPolies.Length(); ++J ) { 00641 if ( CClassify::Polygon( _vPolies[J], _vPolies[I].Plane(), _fThickness ) == LSM_PI_BACK ) { 00642 return false; 00643 } 00644 // Check against the plane polygons too. 00645 for ( LSUINT32 J = _vPlanePolies.Length(); J--; ) { 00646 if ( CClassify::Polygon( _vPlanePolies[J], _vPolies[I].Plane(), _fThickness ) == LSM_PI_BACK ) { return false; } 00647 } 00648 } 00649 } 00650 return true; 00651 } 00652 00659 LSBOOL LSE_CALL AllAreSplitters( const CVector<_tPolyType, LSUINT32, 4096UL> &_vPolies ) { 00660 for ( LSUINT32 I = _vPolies.Length(); I--; ) { 00661 if ( !_vPolies[I].IsSplitter() ) { return false; } 00662 } 00663 return true; 00664 } 00665 00666 }; 00667 00668 } // namespace lsp 00669 00670 #endif // __LSP_SOLIDLEAFBSPBASE_H__