#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUGWATCH #include #include #include #endif #ifdef RAD_DEBUG #include #include #include #include #include #endif #include #include #ifdef RAD_GAMECUBE #include #endif #define TEST_DISTRIBUTED_SORT #define ZSORT_RENDER //#define TRACK_SHADERS //#define TEST_WHOLE_TREE //For debug section //#include { inline bool operator() ( IEntityDSG* pArg1, IEntityDSG* pArg2 ) { return pArg1->mRank < pArg2->mRank; } }; struct gShaderCompare : public std::binary_function< const WorldScene::zSortBlah&, const WorldScene::zSortBlah&, bool > { inline bool operator() ( const WorldScene::zSortBlah& pArg1, const WorldScene::zSortBlah& pArg2 ) { return pArg1.shaderUID < pArg2.shaderUID; } }; struct gTestZ : public std::binary_function< IEntityDSG*, IEntityDSG*, bool > { inline bool operator() ( IEntityDSG* pArg1, IEntityDSG* pArg2 ) { return pArg1->mRank < pArg2->mRank; } }; struct gTestShader : public std::binary_function< IEntityDSG*, IEntityDSG*, bool > { inline bool operator() ( IEntityDSG* pArg1, IEntityDSG* pArg2 ) { return pArg1->GetShaderUID() < pArg2->GetShaderUID(); } }; /*int gZSortCompare( const void *arg1, const void *arg2 ) { return (int)(0.1f*((*(IEntityDSG**)arg1)->Rank() - (*(IEntityDSG**)arg2)->Rank())); } int gShaderCompare( const void *arg1, const void *arg2 ) { return (int)(((WorldScene::zSortBlah*)arg1)->shaderUID - ((WorldScene::zSortBlah*)arg2)->shaderUID); } bool gTestZ( IEntityDSG* arg1, IEntityDSG* arg2 ) { if( arg1->mRank < arg2->mRank ) return true; else return false; // return (int)(0.1f*(arg1->Rank() - arg2->Rank())); } bool gTestShader( IEntityDSG* arg1, IEntityDSG* arg2 ) { if( arg1->mShaderUID < arg2->mShaderUID ) return true; else return false; //return (int)(arg1->GetShaderUID() - arg2->GetShaderUID()); }*/ #endif //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// WorldScene::WorldScene() : mEpsilonOffset(0.01f,0.01f,0.01f), mRenderAll(false), mpStaticTree(NULL) { GetEventManager()->AddListener(this,(EventEnum)(EVENT_LOCATOR+LocatorEvent::FAR_PLANE)); mDrawDist = 200.0f; mpZSorts.reserve(5000); rTuneAssert( mpZSorts.capacity() == 5000 ); mpZSortsPass2.reserve(5000); rTuneAssert( mpZSortsPass2.capacity() == 5000 ); mShadowCastersPass1.Allocate(300); //mShadowCastersPass2.Allocate(300); mCamPlanes.Allocate(6); mpZSortsPassShadowCasters.reserve(300); #ifdef DEBUGWATCH radDbgWatchAddUnsignedInt( &mDebugZSWalkTiming, "ZSort Walk micros", "WorldScene", NULL, NULL ); radDbgWatchAddUnsignedInt( &mDebugZSAddTiming, "ZSort Add micros", "WorldScene", NULL, NULL ); radDbgWatchAddUnsignedInt( &mDebugZSSortTiming, "ZSort Sort micros", "WorldScene", NULL, NULL ); radDbgWatchAddUnsignedInt( &mDebugMarkTiming, "Debug Mark micros", "WorldScene", NULL, NULL ); radDbgWatchAddUnsignedInt( &mDebugWalkTiming, "Debug Walk micros", "WorldScene", NULL, NULL ); radDbgWatchAddUnsignedInt( &mDebugRenderTiming, "Debug Render micros", "WorldScene", NULL, NULL ); mDebugShowTree=false; radDbgWatchAddBoolean(&mDebugShowTree, "ShowTree", "WorldScene", NULL, NULL); // toggle collision volume drawing on and off mDebugSimCollisionVolumeDrawing = false; radDbgWatchAddBoolean(&mDebugSimCollisionVolumeDrawing, "Sim Collision Volume Drawing", "Physics Debug", NULL, NULL); mDebugVehicleCollisionDrawing = false; radDbgWatchAddBoolean(&mDebugVehicleCollisionDrawing, "Vehicle Collision Volume", "Physics Debug", NULL, NULL); mDebugFenceCollisionVolumeDrawing = false; radDbgWatchAddBoolean(&mDebugFenceCollisionVolumeDrawing, "Fence Pieces in Active Area", "Physics Debug", NULL, NULL); mDebugSimStatsDisplay = false; radDbgWatchAddBoolean(&mDebugSimStatsDisplay, "Sim Stats Display", "Physics Debug", NULL, NULL); mDebugWatchNumCollisionPairs = 0; radDbgWatchAddInt(&mDebugWatchNumCollisionPairs, "Num Collision Pairs", "Physics Debug", NULL, NULL ); #endif } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// WorldScene::~WorldScene() { GetEventManager()->RemoveListener(this,(EventEnum)(EVENT_LOCATOR+LocatorEvent::FAR_PLANE)); int i; /* for( i=mStaticIntersects.mUseSize-1; i>-1; i-- ) { mStaticIntersects[i]->Release(); }*/ #ifdef DEBUGWATCH radDbgWatchDelete(&mDebugMarkTiming); radDbgWatchDelete(&mDebugWalkTiming); radDbgWatchDelete(&mDebugRenderTiming); radDbgWatchDelete(&mDebugZSWalkTiming); radDbgWatchDelete(&mDebugZSAddTiming); radDbgWatchDelete(&mDebugZSSortTiming); radDbgWatchDelete(&mDebugShowTree); radDbgWatchDelete(&mDebugSimCollisionVolumeDrawing); radDbgWatchDelete(&mDebugVehicleCollisionDrawing); radDbgWatchDelete(&mDebugFenceCollisionVolumeDrawing); radDbgWatchDelete(&mDebugSimStatsDisplay); radDbgWatchDelete(&mDebugWatchNumCollisionPairs); #endif if(mpStaticTree == NULL) return; for(i=mStaticTreeWalker.NumNodes()-1; i>-1; i--) { rTuneAssert( mStaticTreeWalker.rIthNode(i).mDPhysElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mFenceElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mSEntityElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mSPhysElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mAnimCollElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mAnimElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mIntersectElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mPathSegmentElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mRoadSegmentElems.mUseSize == 0 ); rTuneAssert( mStaticTreeWalker.rIthNode(i).mTrigVolElems.mUseSize == 0 ); } mpStaticTree->ReleaseVerified(); // mpDefaultShader->Release(); } //======================================================================== // worldscene:: //======================================================================== // // Description: adapted from http://www.magic-software.com , David Eberly // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::SetVisCone( rmt::Vector& irView, rmt::Vector& irPosn, float iAngleRadians ) { mViewVector = irView; mViewPosn = irPosn; mViewSinInv = rmt::Sin(iAngleRadians); mViewSinSqr = mViewSinInv*mViewSinInv; mViewSinInv = 1.0f/mViewSinInv; mViewCosSqr = rmt::Cos(iAngleRadians); mViewCosSqr = mViewCosSqr * mViewCosSqr; //mVisUBase.Div( irView, mViewSin ); //mVisUBase } //======================================================================== // worldscene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== bool WorldScene::IsSphereInCone( rmt::Vector& irCenter, float iRadius ) { if ( mRenderAll ) { return true; } // nv: cull small things that are far away const float SMALL_THING = 0.85f; const float SMALL_THING_CULL_DIST_SQR = 4000.0f; // 40m rmt::Vector v; v.Sub(mViewPosn, irCenter); if( (iRadius < SMALL_THING) && (v.MagnitudeSqr() > SMALL_THING_CULL_DIST_SQR) ) { return false; } float Dsqr, e; rmt::Vector bigD, temp1, temp2; temp2 = mViewPosn; temp1 = mViewVector; temp1.Scale(iRadius*mViewSinInv); temp2.Sub(temp1); bigD.Sub(irCenter,temp2); Dsqr = bigD.Dot(bigD); e = mViewVector.Dot(bigD); if( e>0.0f && e*e >= Dsqr*mViewCosSqr ) { bigD.Sub(irCenter,mViewPosn); Dsqr = bigD.Dot(bigD); e = -1.0f*mViewVector.Dot(bigD); if(e>0.0f && e*e > Dsqr*mViewSinSqr) return Dsqr <= iRadius*iRadius; else return true; } return false; } //======================================================================== // worldscene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::HandleEvent( EventEnum id, void* pEventData ) { if(id==EVENT_LOCATOR+LocatorEvent::FAR_PLANE) { unsigned int newDrawDist = ((EventLocator*)pEventData)->GetData(); if(((EventLocator*)pEventData)->GetPlayerID()<1) { if(((EventLocator*)pEventData)->GetPlayerEntered()) { mDrawDist = rmt::LtoF(newDrawDist); } else //exit { mDrawDist = 200.0f; } } return; } rAssert(false); } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::SetTree( SpatialTree* ipSpatialTree ) { rAssert( IsPreTreeGen() ); mpStaticTree = ipSpatialTree; mpStaticTree->AddRef(); mStaticTreeWalker.SetToRoot( *mpStaticTree ); mStaticTreeWalker.AndTree(0x00000000); GenerateSpatialReps(); } //////////////////////////////////////////////////////////////////// // Init will intialise the WorldScene Object: // -Tells WorldScene at maximum how many nRenderables will be // Add'ed // -Is a neccessary precursor to any and all other calls to this // object //////////////////////////////////////////////////////////////////// void WorldScene::Init( int nRenderables ) { rAssert( IsPreTreeGen() ); /* mStaticGeos.Allocate( nRenderables ); mStaticIntersects.Allocate( nRenderables ); mStaticEntities.Allocate( nRenderables ); mStaticPhys.Allocate( nRenderables ); */ } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// void WorldScene::Add( tGeometry* pGeometry ) { // pGeometry->AddRef(); // if( IsNotInScene( pGeometry )) // { // mStaticGeos.Add(pGeometry); // } if( IsPostTreeGen() ) { //todo: uncomment and fix control flow // PlaceStaticGeo( pGeometry ); } } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// void WorldScene::Add( IntersectDSG* ipIntersectDSG ) { // ipIntersectDSG->AddRef(); /// if( IsNotInScene( ipIntersectDSG )) { // mStaticIntersects.Add(ipIntersectDSG); // if( IsPostTreeGen() ) rAssert( IsPostTreeGen() ); { Place( ipIntersectDSG ); } } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( StaticPhysDSG* ipStaticPhysDSG ) { ipStaticPhysDSG->AddRef(); // if( IsNotInScene( ipStaticPhysDSG )) // { // mStaticPhys.Add(ipStaticPhysDSG); rAssert( IsPostTreeGen() ); // if( IsPostTreeGen() ) { Place( ipStaticPhysDSG ); } // } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( StaticEntityDSG* ipStaticEntityDSG ) { // if( IsNotInScene( ipStaticEntityDSG )) // { // mStaticEntities.Add(ipStaticEntityDSG); bool isPostTreeGen = IsPostTreeGen(); rAssert( isPostTreeGen ); if( IsPostTreeGen() ) { ipStaticEntityDSG->AddRef(); Place( ipStaticEntityDSG ); } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( FenceEntityDSG* ipFenceEntityDSG ) { ipFenceEntityDSG->AddRef(); // if( IsNotInScene( ipStaticEntityDSG )) // { // mFenceEntities.Add(ipFenceEntityDSG ); rAssert( IsPostTreeGen() ); // if( IsPostTreeGen() ) { Place( ipFenceEntityDSG ); } // } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( AnimCollisionEntityDSG* ipAnimCollDSG ) { ipAnimCollDSG->AddRef(); rAssert( IsPostTreeGen() ); Place( ipAnimCollDSG ); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( AnimEntityDSG* ipAnimDSG ) { ipAnimDSG->AddRef(); rAssert( IsPostTreeGen() ); Place( ipAnimDSG ); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( DynaPhysDSG* ipDynaPhysDSG ) { ipDynaPhysDSG->AddRef(); rAssert( IsPostTreeGen() ); Place( ipDynaPhysDSG ); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( TriggerVolume* ipTriggerVolume ) { ipTriggerVolume->AddRef(); rAssert(IsPostTreeGen()); Place( ipTriggerVolume ); } //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( RoadSegment* ipRoadSegment ) { ipRoadSegment->AddRef(); rAssert(IsPostTreeGen()); Place( ipRoadSegment ); } //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Add( PathSegment* ipPathSegment ) { ipPathSegment->AddRef(); rAssert(IsPostTreeGen()); Place( ipPathSegment ); } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// void WorldScene::GenerateSpatialReps() { /* mpDefaultShader = p3d::find("OakL_m"); tTexture* pTexture = p3d::find("OakL.bmp"); for(int j=mStaticGeos.mUseSize-1; j>-1; j--) { for( int i=mStaticGeos[j]->GetNumPrimGroup()-1; i>-1; i-- ) { // mStaticGeos[j]->GetShader(i)->SetTexture(PDDI_SP_BASETEX, pTexture); if( mStaticGeos[j]->GetShader(i)->GetType() == mpDefaultShader->GetType() ) { // mStaticGeos[j]->SetShader(i, mpDefaultShader); } } } */ if( IsPreTreeGen() ) { GenerateStaticTree(); } //temporary to ignore weird bounding values mStaticTreeWalker.rBBox().mBounds.mMin.y = -200.0f; mStaticTreeWalker.rBBox().mBounds.mMax.y = 100.0f; mStaticTreeWalker.BuildBBoxes(mStaticTreeWalker.rBBox()); PopulateStaticTree(); } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::Move( rmt::Box3D& irOldBBox, IEntityDSG* ipEDSG ) { /* if(RemovePlace(ipEDSG, mStaticTreeWalker.rIthNode(0))) return; BoxPts aBBox; aBBox.mBounds.mMin.SetTo(irOldBBox.low); aBBox.mBounds.mMax.SetTo(irOldBBox.high); aBBox.mBounds.mMin.Add(mEpsilonOffset); aBBox.mBounds.mMax.Sub(mEpsilonOffset); if(RemovePlace(ipEDSG, mStaticTreeWalker.rSeekNode( aBBox ))) return; */ if(ipEDSG->mpSpatialNode) { if(RemovePlace(ipEDSG, *(ipEDSG->mpSpatialNode) )) return; } rTunePrintf("Move: Can't find ipEDSG: %s, which needs to be moved in the DSG\n", ipEDSG->GetName()); // rAssert(false); } bool WorldScene::RemovePlace(IEntityDSG* ipEDSG, SpatialNode& irNode) { int i; for(i=irNode.mDPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mDPhysElems[i] ) { irNode.mDPhysElems.Remove(i); Place((DynaPhysDSG*)(ipEDSG)); return true; } } for(i=irNode.mAnimCollElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mAnimCollElems[i] ) { irNode.mAnimCollElems.Remove(i); Place((AnimCollisionEntityDSG*)(ipEDSG)); return true; } } for(i=irNode.mAnimElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mAnimElems[i] ) { irNode.mAnimElems.Remove(i); Place((AnimEntityDSG*)(ipEDSG)); return true; } } for(i=irNode.mTrigVolElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mTrigVolElems[i] ) { irNode.mTrigVolElems.Remove(i); Place((TriggerVolume*)(ipEDSG)); return true; } } for(i=irNode.mSEntityElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mSEntityElems[i] ) { irNode.mSEntityElems.Remove(i); Place((StaticEntityDSG*)(ipEDSG)); return true; } } for(i=irNode.mSPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == irNode.mSPhysElems[i] ) { irNode.mSPhysElems.Remove(i); Place((StaticPhysDSG*)(ipEDSG)); return true; } } return false; } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::Remove( IEntityDSG* ipEDSG ) { //if( RemoveFromLeaf(ipEDSG) ) // return; int i; /* BoxPts aBBox; rmt::Box3D Box3DBBox; ipEDSG->GetBoundingBox(&Box3DBBox); aBBox.mBounds.mMin.SetTo(Box3DBBox.low); aBBox.mBounds.mMax.SetTo(Box3DBBox.high); aBBox.mBounds.mMin.Add(mEpsilonOffset); aBBox.mBounds.mMax.Sub(mEpsilonOffset); SpatialNode& rNode = mStaticTreeWalker.rSeekNode( aBBox ); */ rAssert(ipEDSG->mpSpatialNode); if(!ipEDSG->mpSpatialNode) { return; } SpatialNode& rNode = *(ipEDSG->mpSpatialNode); ipEDSG->mpSpatialNode = NULL; for(i=rNode.mDPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mDPhysElems[i] ) { rNode.mDPhysElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mSEntityElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mSEntityElems[i] ) { rNode.mSEntityElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mSPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mSPhysElems[i] ) { rNode.mSPhysElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mIntersectElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mIntersectElems[i] ) { rNode.mIntersectElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mTrigVolElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mTrigVolElems[i] ) { rNode.mTrigVolElems.Remove(i); ipEDSG->Release(); return; } } rTunePrintf("Remove: Can't find ipEDSG: %s, which needs to be removed in the DSG\n", ipEDSG->GetName()); rAssert(false); } bool WorldScene::RemoveFromLeaf( IEntityDSG* ipEDSG ) { SpatialNode& rNode = mStaticTreeWalker.rIthNode(0); int i; for(i=rNode.mDPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mDPhysElems[i] ) { rNode.mDPhysElems.Remove(i); ipEDSG->Release(); return true; } } for(i=rNode.mSEntityElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mSEntityElems[i] ) { rNode.mSEntityElems.Remove(i); ipEDSG->Release(); return true; } } for(i=rNode.mAnimCollElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mAnimCollElems[i] ) { rNode.mAnimCollElems.Remove(i); ipEDSG->Release(); return true; } } for(i=rNode.mAnimElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mAnimElems[i] ) { rNode.mAnimCollElems.Remove(i); ipEDSG->Release(); return true; } } return false; } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::RemoveQuietFail( IEntityDSG* ipEDSG ) { //if( RemoveFromLeaf(ipEDSG) ) // return; int i; /* BoxPts aBBox; rmt::Box3D Box3DBBox; ipEDSG->GetBoundingBox(&Box3DBBox); aBBox.mBounds.mMin.SetTo(Box3DBBox.low); aBBox.mBounds.mMax.SetTo(Box3DBBox.high); aBBox.mBounds.mMin.Add(mEpsilonOffset); aBBox.mBounds.mMax.Sub(mEpsilonOffset); SpatialNode& rNode = mStaticTreeWalker.rSeekNode( aBBox ); */ if(!ipEDSG->mpSpatialNode) { rDebugPrintf("RemoveQuietFail: Can't find ipEDSG: %s, which needs to be moved in the DSG\n", ipEDSG->GetName()); return; } SpatialNode& rNode = *(ipEDSG->mpSpatialNode); ipEDSG->mpSpatialNode = NULL; for(i=rNode.mDPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mDPhysElems[i] ) { rNode.mDPhysElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mSEntityElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mSEntityElems[i] ) { rNode.mSEntityElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mSPhysElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mSPhysElems[i] ) { rNode.mSPhysElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mIntersectElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mIntersectElems[i] ) { rNode.mIntersectElems.Remove(i); ipEDSG->Release(); return; } } for(i=rNode.mTrigVolElems.mUseSize-1;i>-1;i--) { if( ipEDSG == rNode.mTrigVolElems[i] ) { rNode.mTrigVolElems.Remove(i); ipEDSG->Release(); return; } } rDebugPrintf("RemoveQuietFail: Can't find ipEDSG: %s, which needs to be moved in the DSG\n", ipEDSG->GetName()); } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::RenderScene( unsigned int iFilter, tPointCamera* ipCam ) { #ifdef TRACK_SHADERS static int sRenderCall=0; sRenderCall++; #endif /* if(!mpTempShader) { mpTempShader = p3d::find("fire_hydrant_m"); rReleaseAssert(mpTempShader); } */ static int sMaxDebugGeoCount = 0; int DebugRenderGeoCount = 0; int DebugRenderNodeCount = 0; int DebugRenderLeafCount = 0; // mpZSorts.ClearUse(); // mpZSortsPass2.ClearUse(); mpZSorts.resize( 0 ); rTuneAssert( mpZSorts.capacity() == 5000 ); mpZSortsPass2.resize( 0 ); rTuneAssert( mpZSortsPass2.capacity() == 5000 ); mpZSortsPassShadowCasters.resize(0); rTuneAssert( mpZSortsPassShadowCasters.capacity() == 300 ); mShadowCastersPass1.ClearUse(); //mShadowCastersPass2.ClearUse(); std::vector > mSort1; std::vector > mSort2; #ifdef DEBUGWATCH // turn off Z compare if we're drawing fence pieces also /* pddiCompareMode restoreZMode; if(mDebugFenceCollisionVolumeDrawing) { restoreZMode = p3d::pddi->GetZCompare(); p3d::pddi->SetZCompare(PDDI_COMPARE_NONE); } */ #endif #ifdef TEST_WHOLE_TREE static int maxDPhys=0,maxSEntity=0,maxAnimColl=0,maxAnimElem=0; int DPhysCount=0, SEntityCount=0, AnimCollCount=0, AnimElemCount=0, temp=0; for( int ith=mStaticTreeWalker.NumNodes()-1; ith>-1; ith--) { SpatialNode& rCurNode = mStaticTreeWalker.rIthNode(ith); temp = rCurNode.mDPhysElems.mUseSize-(rCurNode.mDPhysElems.mSize-50); if(temp>0) DPhysCount+=temp; temp = rCurNode.mSEntityElems.mUseSize-(rCurNode.mSEntityElems.mSize-32); if(temp>0) SEntityCount+=temp; AnimCollCount+=rCurNode.mAnimCollElems.mUseSize; AnimElemCount+=rCurNode.mAnimElems.mUseSize; } if(DPhysCount > maxDPhys) maxDPhys = DPhysCount; if(SEntityCount > maxSEntity) maxSEntity = SEntityCount; if(AnimCollCount > maxAnimColl) maxAnimColl = AnimCollCount; if(AnimElemCount > maxAnimElem) maxAnimElem = AnimElemCount; #endif mStaticTreeWalker.SetIterFilter( iFilter ); ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH mDebugZSAddTiming = 0; unsigned int t0,t1,tRenderAcc=0; t0 = radTimeGetMicroseconds(); mDebugZSWalkTiming = radTimeGetMicroseconds(); #endif BEGIN_PROFILE("list construction") #ifdef TRACK_SHADERS typedef std::map< tUID, int, std::less, s2alloc< std::pair< const tUID, int > > > UIDMap; UIDMap UniqueShaders; #endif //Hack #ifdef RAD_DEBUG if(0)//GetMissionManager()->GetCurrentMission()->GetState()==Mission::STATE_INPROGRESS && //!GetMissionManager()->InResetState() && //GetGameFlow()->GetCurrentContext() == CONTEXT_GAMEPLAY) { rmt::Matrix Trans; rmt::Vector testPosn; pddiPrimStream* stream; GetAvatarManager()->GetAvatarForPlayer(0)->GetPosition(testPosn); Trans.Identity(); Trans.FillTranslate(GetMissionManager()->GetCurrentMission()->GetCurrentStage()->GetObjective()->mPathStart); p3d::pddi->PushMatrix(PDDI_MATRIX_MODELVIEW); p3d::pddi->MultMatrix(PDDI_MATRIX_MODELVIEW,&Trans); stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 2); stream->Colour(tColour(255,0,0)); stream->Coord(0.0f, 0.0f, 0.0f); stream->Colour(tColour(255,0,0)); stream->Coord(0.0f, 2.0f, 0.0f); p3d::pddi->EndPrims(stream); p3d::pddi->PopMatrix(PDDI_MATRIX_MODELVIEW); Trans.Identity(); Trans.FillTranslate(GetMissionManager()->GetCurrentMission()->GetCurrentStage()->GetObjective()->mPathEnd); p3d::pddi->PushMatrix(PDDI_MATRIX_MODELVIEW); p3d::pddi->MultMatrix(PDDI_MATRIX_MODELVIEW,&Trans); stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 2); stream->Colour(tColour(0,255,0)); stream->Coord(0.0f, 0.0f, 0.0f); stream->Colour(tColour(0,255,0)); stream->Coord(0.0f, 2.0f, 0.0f); p3d::pddi->EndPrims(stream); p3d::pddi->PopMatrix(PDDI_MATRIX_MODELVIEW); } #endif rmt::Sphere ObjectSphere; rmt::Vector CamPosn = ipCam->GetPosition(); ////////////////////////////////////////////////////////////////////////// //For all the visible nodes in the tree //#ifdef DEBUGWATCH pddiCompareMode origZCompare = p3d::pddi->GetZCompare(); //#endif DebugRenderNodeCount = 0; for( mStaticTreeWalker.MoveToFirst(); mStaticTreeWalker.NotDone(); mStaticTreeWalker.MoveToNext(true) ) { DebugRenderNodeCount++; if(GetCheatInputSystem()->IsCheatEnabled(CHEAT_ID_SHOW_TREE)) { if( mStaticTreeWalker.IsCurrentLeaf() ) { DebugRenderLeafCount++; //#ifdef DEBUGWATCH // if(mDebugShowTree) { p3d::pddi->SetZCompare(PDDI_COMPARE_ALWAYS); mStaticTreeWalker.DisplayCurrentBoundingBox( tColour(255,0,0) ); p3d::pddi->SetZCompare(origZCompare); } //#endif } else { //#ifdef DEBUGWATCH // if(mDebugShowTree) { p3d::pddi->SetZCompare(PDDI_COMPARE_ALWAYS); mStaticTreeWalker.DisplayCurrentBoundingBox( tColour(0,0,0) ); p3d::pddi->SetZCompare(origZCompare); } //#endif //rAssert( mStaticTreeWalker.pCurrent()->mSpatialElems.mSize == 0 ); //rAssert( mStaticTreeWalker.pCurrent()->mSpatialElems.mUseSize == 0 ); // rAssert( mStaticTreeWalker.pCurrent()->mIntersectElems.mSize == 0 ); // rAssert( mStaticTreeWalker.pCurrent()->mIntersectElems.mUseSize == 0 ); } } // if( BEGIN_DEBUGINFO_SECTION( "CullDebug" ) ) // { //mStaticTreeWalker.DisplayCurrentBoundingBox( tColour(255,255,0) ); // } // END_DEBUGINFO_SECTION; #if 1 ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #endif //For all the Used slots in the node's T array int i; ////////////////////////////////////////////////////////////////////////// for( i= mStaticTreeWalker.rCurrent().mSEntityElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER mStaticTreeWalker.rCurrent().mSEntityElems[i]->GetBoundingSphere(&ObjectSphere); if(!IsSphereInCone(ObjectSphere.centre, ObjectSphere.radius)) continue; //mStaticTreeWalker.rCurrent().mSEntityElems[i]->SetShader(mpTempShader,0); switch(3)//mStaticTreeWalker.rCurrent().mSEntityElems[i]->CastsShadow()) { case 1: mShadowCastersPass1.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSEntityElems[i]); break; case 2: { //mShadowCastersPass2.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSEntityElems[i]); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mSEntityElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPassShadowCasters.push_back( newDSGPtr ); } break; default: if(!mStaticTreeWalker.rCurrent().mSEntityElems[i]->mTranslucent && mStaticTreeWalker.rCurrent().mSEntityElems[i]->CastsShadow()==0) { //mpZSorts.AddUse(1); //mpZSorts[mpZSorts.mUseSize-1].entityPtr = mStaticTreeWalker.rCurrent().mSEntityElems[i]; //mpZSorts[mpZSorts.mUseSize-1].shaderUID = mpZSorts[mpZSorts.mUseSize-1].entityPtr->GetShaderUID(); zSortBlah newBlah; newBlah.entityPtr = mStaticTreeWalker.rCurrent().mSEntityElems[i]; newBlah.shaderUID = newBlah.entityPtr->GetShaderUID(); mpZSorts.push_back( newBlah ); //mpZSorts[mpZSorts.mUseSize-1]->SetRank((rmt::Vector&)ipCam->GetPosition()); //mSort1.push_back(mStaticTreeWalker.rCurrent().mSEntityElems[i]); } else { //mpZSortsPass2.AddUse(1); //mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mSEntityElems[i]; //mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mSEntityElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPass2.push_back( newDSGPtr ); //mSort2.push_back(mStaticTreeWalker.rCurrent().mSEntityElems[i]); } break; } #else switch(mStaticTreeWalker.rCurrent().mSEntityElems[i]->CastsShadow()) { mShadowCasters.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSEntityElems[i]); } else { mStaticTreeWalker.rCurrent().mSEntityElems[i]->Display(); } #endif DebugRenderGeoCount++; } ////////////////////////////////////////////////////////////////////////// for( i= mStaticTreeWalker.rCurrent().mAnimCollElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER mStaticTreeWalker.rCurrent().mAnimCollElems[i]->GetBoundingSphere(&ObjectSphere); if(!IsSphereInCone(ObjectSphere.centre, ObjectSphere.radius)) continue; switch(3)//mStaticTreeWalker.rCurrent().mAnimCollElems[i]->CastsShadow()) { case 1: mShadowCastersPass1.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimCollElems[i]); break; case 2: { //mShadowCastersPass2.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimCollElems[i]); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mAnimCollElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPassShadowCasters.push_back( newDSGPtr ); } break; default: if(!mStaticTreeWalker.rCurrent().mAnimCollElems[i]->mTranslucent && mStaticTreeWalker.rCurrent().mAnimCollElems[i]->CastsShadow()==0) { //mpZSorts.AddUse(1); //mpZSorts[mpZSorts.mUseSize-1].entityPtr = mStaticTreeWalker.rCurrent().mAnimCollElems[i]; //mpZSorts[mpZSorts.mUseSize-1].shaderUID = mpZSorts[mpZSorts.mUseSize-1].entityPtr->GetShaderUID(); zSortBlah newBlah; newBlah.entityPtr = mStaticTreeWalker.rCurrent().mAnimCollElems[i]; newBlah.shaderUID = newBlah.entityPtr->GetShaderUID(); mpZSorts.push_back( newBlah ); //mpZSorts[mpZSorts.mUseSize-1]->SetRank(CamPosn); //mSort1.push_back(mStaticTreeWalker.rCurrent().mAnimCollElems[i]); } else { //mpZSortsPass2.AddUse(1); //mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mAnimCollElems[i]; //mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); IEntityDSG* pDSGPtr = mStaticTreeWalker.rCurrent().mAnimCollElems[i];; pDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPass2.push_back( pDSGPtr ); //mSort2.push_back(mStaticTreeWalker.rCurrent().mAnimCollElems[i]); } } #else if(mStaticTreeWalker.rCurrent().mAnimCollElems[i]->CastsShadow()) { mShadowCasters.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimCollElems[i]); } else { mStaticTreeWalker.rCurrent().mAnimCollElems[i]->Display(); } #endif DebugRenderGeoCount++; } ////////////////////////////////////////////////////////////////////////// for( i= mStaticTreeWalker.rCurrent().mAnimElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER // if( mStaticTreeWalker.rCurrent().mAnimElems[i]->GetUID() == tName::MakeUID("smokecolumn") ) // rReleasePrintf("n"); mStaticTreeWalker.rCurrent().mAnimElems[i]->GetBoundingSphere(&ObjectSphere); if(!IsSphereInCone(ObjectSphere.centre, ObjectSphere.radius)) continue; switch(3)//mStaticTreeWalker.rCurrent().mAnimElems[i]->CastsShadow()) { case 1: mShadowCastersPass1.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimElems[i]); break; case 2: { //mShadowCastersPass2.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimElems[i]); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mAnimElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPassShadowCasters.push_back( newDSGPtr ); } break; default: if(!mStaticTreeWalker.rCurrent().mAnimElems[i]->mTranslucent && mStaticTreeWalker.rCurrent().mAnimElems[i]->CastsShadow()==0) { //mpZSorts.AddUse(1); //mpZSorts[mpZSorts.mUseSize-1].entityPtr = mStaticTreeWalker.rCurrent().mAnimElems[i]; //mpZSorts[mpZSorts.mUseSize-1].shaderUID = mpZSorts[mpZSorts.mUseSize-1].entityPtr->GetShaderUID(); zSortBlah newBlah; newBlah.entityPtr = mStaticTreeWalker.rCurrent().mAnimElems[i]; newBlah.shaderUID = newBlah.entityPtr->GetShaderUID(); mpZSorts.push_back( newBlah ); //mpZSorts[mpZSorts.mUseSize-1]->SetRank(CamPosn); //mSort1.push_back(mStaticTreeWalker.rCurrent().mAnimElems[i]); } else { // mpZSortsPass2.AddUse(1); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mAnimElems[i]; newDSGPtr->SetRank(CamPosn,mViewVector); mpZSortsPass2.push_back( newDSGPtr ); //mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mAnimElems[i]; //mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); //mSort2.push_back(mStaticTreeWalker.rCurrent().mAnimElems[i]); } } #else if(mStaticTreeWalker.rCurrent().mAnimElems[i]->CastsShadow()) { mShadowCasters.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mAnimElems[i]); } else { mStaticTreeWalker.rCurrent().mAnimElems[i]->Display(); } #endif DebugRenderGeoCount++; } ////////////////////////////////////////////////////////////////////////// for( i= mStaticTreeWalker.rCurrent().mDPhysElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER #ifdef DEBUGWATCH // unsigned int dbwt=radTimeGetMicroseconds(); #endif mStaticTreeWalker.rCurrent().mDPhysElems[i]->GetBoundingSphere(&ObjectSphere); if(!IsSphereInCone(ObjectSphere.centre, ObjectSphere.radius)) continue; switch(mStaticTreeWalker.rCurrent().mDPhysElems[i]->CastsShadow()) { /* case 1: mShadowCastersPass1.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mDPhysElems[i]); break; case 2: { //mShadowCastersPass2.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mDPhysElems[i]); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mDPhysElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPassShadowCasters.push_back( newDSGPtr ); } break; */ case 989: // <--Vehicle code // Dump the vehicle into the mpZSortsPassShadowCasters array so that // displaysimpleshadow will be called on it, also let it slide into the // default case, so that it gets tossed into the normal mpZSorts (normal // translucent object { IEntityDSG* object = mStaticTreeWalker.rCurrent().mDPhysElems[i]; rTuneAssert( dynamic_cast< Vehicle* >( object ) != NULL ); mShadowCastersPass1.Add( object ); } default: if(!mStaticTreeWalker.rCurrent().mDPhysElems[i]->mTranslucent && mStaticTreeWalker.rCurrent().mDPhysElems[i]->CastsShadow()==0) { // mpZSorts.AddUse(1); //mpZSorts[mpZSorts.mUseSize-1].entityPtr = mStaticTreeWalker.rCurrent().mDPhysElems[i]; //mpZSorts[mpZSorts.mUseSize-1].shaderUID = mpZSorts[mpZSorts.mUseSize-1].entityPtr->GetShaderUID(); zSortBlah newBlah; newBlah.entityPtr = mStaticTreeWalker.rCurrent().mDPhysElems[i]; newBlah.shaderUID = newBlah.entityPtr->GetShaderUID(); mpZSorts.push_back( newBlah ); //mpZSorts[mpZSorts.mUseSize-1]->SetRank(CamPosn); //mSort1.push_back(mStaticTreeWalker.rCurrent().mDPhysElems[i]); } else { IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mDPhysElems[i]; newDSGPtr->SetRank(CamPosn,mViewVector); mpZSortsPass2.push_back( newDSGPtr ); //mpZSortsPass2.AddUse(1); //mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mDPhysElems[i]; //mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); //mSort2.push_back(mStaticTreeWalker.rCurrent().mDPhysElems[i]); } } #ifdef DEBUGWATCH // mDebugZSAddTiming += radTimeGetMicroseconds()-dbwt; #endif #else if(mStaticTreeWalker.rCurrent().mDPhysElems[i]->CastsShadow()) { mShadowCasters.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mDPhysElems[i]); } else { mStaticTreeWalker.rCurrent().mDPhysElems[i]->Display(); } #endif DebugRenderGeoCount++; } ////////////////////////////////////////////////////////////////////////// for( i= mStaticTreeWalker.rCurrent().mSPhysElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER #ifdef DEBUGWATCH // unsigned int dbwt=radTimeGetMicroseconds(); #endif mStaticTreeWalker.rCurrent().mSPhysElems[i]->GetBoundingSphere(&ObjectSphere); if(!IsSphereInCone(ObjectSphere.centre, ObjectSphere.radius)) continue; switch(3)//mStaticTreeWalker.rCurrent().mSPhysElems[i]->CastsShadow()) { case 1: mShadowCastersPass1.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSPhysElems[i]); break; case 2: { //mShadowCastersPass2.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSPhysElems[i]); IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mSPhysElems[i]; newDSGPtr->SetRank( CamPosn, mViewVector ); mpZSortsPassShadowCasters.push_back( newDSGPtr ); } break; default: if(!mStaticTreeWalker.rCurrent().mSPhysElems[i]->mTranslucent && mStaticTreeWalker.rCurrent().mSPhysElems[i]->CastsShadow()==0) { //mpZSorts.AddUse(1); //mpZSorts[mpZSorts.mUseSize-1].entityPtr = mStaticTreeWalker.rCurrent().mSPhysElems[i]; //mpZSorts[mpZSorts.mUseSize-1].shaderUID = mpZSorts[mpZSorts.mUseSize-1].entityPtr->GetShaderUID(); zSortBlah newBlah; newBlah.entityPtr = mStaticTreeWalker.rCurrent().mSPhysElems[i]; newBlah.shaderUID = newBlah.entityPtr->GetShaderUID(); mpZSorts.push_back( newBlah ); //mpZSorts[mpZSorts.mUseSize-1]->SetRank(CamPosn); //mSort1.push_back(mStaticTreeWalker.rCurrent().mSPhysElems[i]); } else { IEntityDSG* newDSGPtr = mStaticTreeWalker.rCurrent().mSPhysElems[i]; newDSGPtr->SetRank(CamPosn, mViewVector); mpZSortsPass2.push_back( newDSGPtr ); //mpZSortsPass2.AddUse(1); //mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mSPhysElems[i]; //mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); //mSort2.push_back(mStaticTreeWalker.rCurrent().mSPhysElems[i]); } } #ifdef DEBUGWATCH // mDebugZSAddTiming += radTimeGetMicroseconds()-dbwt; #endif #else if(mStaticTreeWalker.rCurrent().mSPhysElems[i]->CastsShadow()) { mShadowCasters.Add((IEntityDSG*&)mStaticTreeWalker.rCurrent().mSPhysElems[i]); } else { mStaticTreeWalker.rCurrent().mSPhysElems[i]->Display(); } #endif DebugRenderGeoCount++; } /* for( i= mStaticTreeWalker.rCurrent().mTrigVolElems.mUseSize-1; i>-1; i-- ) { #ifdef ZSORT_RENDER #ifdef DEBUGWATCH // unsigned int dbwt=radTimeGetMicroseconds(); #endif if(!mStaticTreeWalker.rCurrent().mTrigVolElems[i]->mTranslucent) { mpZSorts.AddUse(1); mpZSorts[mpZSorts.mUseSize-1] = mStaticTreeWalker.rCurrent().mTrigVolElems[i]; //mpZSorts[mpZSorts.mUseSize-1]->SetRank(CamPosn); //mSort1.push_back(mStaticTreeWalker.rCurrent().mTrigVolElems[i]); } else { mpZSortsPass2.AddUse(1); mpZSortsPass2[mpZSortsPass2.mUseSize-1] = mStaticTreeWalker.rCurrent().mTrigVolElems[i]; mpZSortsPass2[mpZSortsPass2.mUseSize-1]->SetRank(CamPosn); //mSort2.push_back(mStaticTreeWalker.rCurrent().mTrigVolElems[i]); } #ifdef DEBUGWATCH // mDebugZSAddTiming += radTimeGetMicroseconds()-dbwt; #endif #else mStaticTreeWalker.rCurrent().mTrigVolElems[i]->Display(); #endif DebugRenderGeoCount++; }*/ } // rAssert(DebugRenderNodeCount<1000); END_PROFILE("list construction") ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #ifdef ZSORT_RENDER #ifdef DEBUGWATCH mDebugZSWalkTiming = radTimeGetMicroseconds()-mDebugZSWalkTiming; mDebugZSSortTiming = radTimeGetMicroseconds(); #endif /* NodeFLL* pHead = &(mpZSorts[mpZSorts.mUseSize-1]); for(int i=mpZSorts.mUseSize-2; i>-1; i--) { pHead = pHead->PlaceHighestFirst(&(mpZSorts[i])); } */ #ifndef RAD_RELEASE BEGIN_PROFILE("STD::sort1") gTestShader shaderTestObj; std::sort(mSort1.begin(),mSort1.end(), shaderTestObj); END_PROFILE("STD::sort1") BEGIN_PROFILE("STD::sort2") gTestZ zTestObj; std::sort(mSort2.begin(),mSort2.end(), zTestObj); END_PROFILE("STD::sort2") #endif #ifndef TEST_DISTRIBUTED_SORT BEGIN_PROFILE("qsort1") //qsort(mpZSorts.mpData, (size_t)mpZSorts.mUseSize, sizeof(zSortBlah), gShaderCompare); gShaderCompare blahShaderCompareObj; std::sort( mpZSorts.begin(), mpZSorts.end(), blahShaderCompareObj ); END_PROFILE("qsort1") BEGIN_PROFILE("qsort2") //qsort(mpZSortsPass2.mpData, (size_t)mpZSortsPass2.mUseSize, sizeof(IEntityDSG*), gZSortCompare); gZSortCompare dsgZSortObj; std::sort( mpZSortsPass2.begin(), mpZSortsPass2.end(), dsgZSortObj ); END_PROFILE("qsort2") #endif //BEGIN_PROFILE("shadow caster zsort") // std::sort( mpZSortsPassShadowCasters.begin(), mpZSortsPassShadowCasters.end(), dsgZSortObj ); //END_PROFILE("shadow caster zsort") #ifdef DEBUGWATCH mDebugZSSortTiming = radTimeGetMicroseconds()-mDebugZSSortTiming; #endif #ifdef TRACK_SHADERS int avgUse=0, totalCount=0, unsortableCount; UIDMap::iterator it; if(sRenderCall==200) { for (it = UniqueShaders.begin(); it != UniqueShaders.end(); it++) { rTunePrintf("UniqueShader %d use count %d\n", (*it).first, (*it).second ); if((*it).first != tName::MakeUID("__none__")) { avgUse += (*it).second; totalCount++; } else { unsortableCount = (*it).second; } } rTunePrintf("Avg Use: %d Total Sortable Count: %d Unsortable Shader Count: %d Alpha Shaders %d\n", avgUse/totalCount, totalCount, unsortableCount, mpZSortsPass2.mUseSize); } #endif ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #endif ////////////////////////////////////////////////////////////////////////// //Debug Collision volumes ////////////////////////////////////////////////////////////////////////// /* ReserveArray& rCollisionElems = mStaticTreeWalker.rCurrent().mDynamicElems; for( int i=rCollisionElems.mUseSize-1; i>-1; i-- ) { rCollisionElems[i]->DisplayBoundingBox(); } */ #ifdef DEBUGWATCH int activeArea = -1; Avatar* av = GetAvatarManager()->GetAvatarForPlayer(0); Vehicle* v = av->GetVehicle(); Character* c = av->GetCharacter(); if(v) { activeArea = v->mCollisionAreaIndex; } else if(c) { activeArea = c->GetCollisionAreaIndex(); } // call to martin's sim display if(mDebugSimCollisionVolumeDrawing && /*v &&*/ activeArea > -1) { sim::DisplayCollisionObjects(GetWorldPhysicsManager()->mCollisionManager, activeArea); } if(mDebugFenceCollisionVolumeDrawing && activeArea > -1) { GetWorldPhysicsManager()->DisplayFencesInArea(activeArea); } if(mDebugVehicleCollisionDrawing && v) { v->DebugDisplay(); v->CarDisplay(false); } else if(v) { v->CarDisplay(true); } if(mDebugSimStatsDisplay) { // this makes things grind to a fucking halt sim::SimStats::DisplayStats(); } if(activeArea > -1) { mDebugWatchNumCollisionPairs = GetWorldPhysicsManager()->mCollisionManager->GetCollisionObjectPairList(activeArea)->GetSize(); } else { mDebugWatchNumCollisionPairs = -1; } // set Z Compare back if(mDebugFenceCollisionVolumeDrawing) { // p3d::pddi->SetZCompare(restoreZMode); } #endif ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH t1 = radTimeGetMicroseconds(); #endif #ifdef DEBUGWATCH tRenderAcc += radTimeGetMicroseconds()-t1; #endif ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH t1 = radTimeGetMicroseconds(); mDebugWalkTiming = t1-t0; mDebugRenderTiming = tRenderAcc; #endif ////////////////////////////////////////////////////////////////////////// if(DebugRenderGeoCount > sMaxDebugGeoCount ) sMaxDebugGeoCount = DebugRenderGeoCount; //Assert: we are not drawing more geometries that we have //(ie, drawing everything twice or something) //rAssert( DebugRenderGeoCount <= mStaticGeos.mUseSize ); } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::RenderShadows() { for( int i=mShadowCastersPass1.mUseSize-1; i>-1; i-- ) { mShadowCastersPass1[i]->DisplayShadow(); } // for( int i=mShadowCastersPass2.mUseSize-1; i>-1; i-- ) // { // mShadowCastersPass2[i]->DisplayShadow(); // } for(int i=mpZSortsPassShadowCasters.size()-1; i>-1; i--) { mpZSortsPassShadowCasters[i]->DisplayShadow(); } } /*======================================================================== Draw simple blob shadows under a character. Don't call within the normal shadow generator setup since the tris won't shade properly. ========================================================================*/ void WorldScene::RenderSimpleShadows( void ) { p3d::pddi->SetZWrite(false); for( int i = 0; i < mShadowCastersPass1.mUseSize; ++i ) { mShadowCastersPass1[ i ]->DisplaySimpleShadow(); } // for( int i = 0; i < mShadowCastersPass2.mUseSize; ++i ) // { // mShadowCastersPass2[ i ]->DisplaySimpleShadow(); // } for(int i=mpZSortsPassShadowCasters.size()-1; i>-1; i--) { mpZSortsPassShadowCasters[i]->DisplaySimpleShadow(); } p3d::pddi->SetZWrite( true ); } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::RenderShadowCasters() { DSG_SET_PROFILE('C') for( int i=mShadowCastersPass1.mUseSize-1; i>-1; i-- ) { // BEGIN_PROFILE("ShadowCastPass1") mShadowCastersPass1[i]->Display(); // END_PROFILE("ShadowCastPass1") } //for( int i=mShadowCastersPass2.mUseSize-1; i>-1; i-- ) //{ // mShadowCastersPass2[i]->Display(); //} for(int i=mpZSortsPassShadowCasters.size()-1; i>-1; i--) { mpZSortsPassShadowCasters[i]->Display(); } } void WorldScene::RenderOpaque( void ) { #ifdef TEST_DISTRIBUTED_SORT BEGIN_PROFILE("qsort1") //qsort(mpZSorts.mpData, (size_t)mpZSorts.mUseSize, sizeof(zSortBlah), gShaderCompare); gShaderCompare blahShaderCompareObj; std::sort( mpZSorts.begin(), mpZSorts.end(), blahShaderCompareObj ); END_PROFILE("qsort1") #endif DSG_SET_PROFILE('O') BEGIN_PROFILE("qsort display") for(int i=mpZSorts.size() - 1; i>-1; i--) { //BEGIN_PROFILE("opaque inner") mpZSorts[i].entityPtr->Display(); #ifdef TRACK_SHADERS UniqueShaders[mpZSorts[i].entityPtr->GetShaderUID()]++; #endif //END_PROFILE("opaque inner") } END_PROFILE("qsort display") } void WorldScene::RenderTranslucent( void ) { #ifdef RAD_GAMECUBE RefractionShader::AllowOneBufferCapture(); #endif #ifdef TEST_DISTRIBUTED_SORT BEGIN_PROFILE("qsort2") //qsort(mpZSortsPass2.mpData, (size_t)mpZSortsPass2.mUseSize, sizeof(IEntityDSG*), gZSortCompare); gZSortCompare dsgZSortObj; std::sort( mpZSortsPass2.begin(), mpZSortsPass2.end(), dsgZSortObj ); END_PROFILE("qsort2") #endif DSG_SET_PROFILE('T') BEGIN_PROFILE("qsort2 display") for(int i=mpZSortsPass2.size()-1; i>-1; i--) { //BEGIN_PROFILE("translucent inner") mpZSortsPass2[i]->Display(); //END_PROFILE("translucent inner") } END_PROFILE("qsort2 display") } //======================================================================== // WorldScene:: //======================================================================== // // Description: // // Parameters: None. // // Return: None. // // Constraints: None. // //======================================================================== void WorldScene::Render( unsigned int viewIndex ) { //mStaticTreeWalker.MarkTree( msVisible ); mStaticTreeWalker.AndTree( msClear ); //mStaticTreeWalker.OrTree( msVisible ); //BEGIN_PROFILE("Mark Camera") tPointCamera* pCam; ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH unsigned int t0, t1; #endif ////////////////////////////////////////////////////////////////////////// switch( viewIndex ) { case 0: { ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH t0 = radTimeGetMicroseconds(); #endif ////////////////////////////////////////////////////////////////////////// pCam = (tPointCamera*)GetSuperCamManager()->GetSCC(0)->GetCamera(); BEGIN_PROFILE("cam viz") if( mRenderAll ) mStaticTreeWalker.OrTreeVis( msVisible0 ); else MarkCameraVisible( pCam, msVisible0 ); END_PROFILE("cam viz") ////////////////////////////////////////////////////////////////////////// #ifdef DEBUGWATCH t1 = radTimeGetMicroseconds(); mDebugMarkTiming = t1-t0; #endif ////////////////////////////////////////////////////////////////////////// RenderScene( msVisible0, pCam ); break; } case 1: { pCam = (tPointCamera*)GetSuperCamManager()->GetSCC(1)->GetCamera(); MarkCameraVisible( pCam, msVisible1 ); RenderScene( msVisible1, pCam ); break; } default: { rAssertMsg(false, "Only supporting 1 or 2 players right now."); break; } } //END_PROFILE("Mark Camera") } //////////////////////////////////////////////////////////////////// //-------------------Private--------------------------------------// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// void WorldScene::GenerateStaticTree() {/* Bounds3f WorldBounds; rmt::Box3D BBox; int i; SpatialTreeFactory StaticTF; StaticTF.Reset( (mStaticIntersects.mUseSize+mStaticGeos.mUseSize) * 2 +2); mStaticGeos[0]->GetBoundingBox( &BBox ); WorldBounds.mMin.SetTo( BBox.low ); WorldBounds.mMax.SetTo( BBox.high ); /////////////////////////////////////////////////////////////////////// // Seed the TreeFactory with data from all the drawable elements /////////////////////////////////////////////////////////////////////// for( i=mStaticGeos.mUseSize-1; i>-1; i-- ) { mStaticGeos[i]->GetBoundingBox( &BBox ); StaticTF.Seed( ((Vector3f&)BBox.low), 0 ); StaticTF.Seed( ((Vector3f&)BBox.high), mStaticGeos[i]->GetNumPrimGroup() ); WorldBounds.Accumulate( (Vector3f&)BBox.low ); WorldBounds.Accumulate( (Vector3f&)BBox.high ); //used to use low, but that'll lead to more bad volume intersects } /////////////////////////////////////////////////////////////////////// // Seed the TreeFactory with data from all the intersect elements /////////////////////////////////////////////////////////////////////// for( i=mStaticIntersects.mUseSize-1; i>-1; i-- ) { mStaticIntersects[i]->GetBoundingBox( &BBox ); StaticTF.Seed( ((Vector3f&)BBox.low), 0 ); StaticTF.Seed( ((Vector3f&)BBox.high), mStaticIntersects[i]->GetNumPrimGroup() ); WorldBounds.Accumulate( (Vector3f&)BBox.low ); WorldBounds.Accumulate( (Vector3f&)BBox.high ); //used to use low, but that'll lead to more bad volume intersects } //Add a coupla bounding seeds; bound correction to handle //p3dsplit/modified, which subdivides from the origin WorldBounds.mMin.x = rmt::Floor(WorldBounds.mMin.x/TODO_GRANULARITY.x)*TODO_GRANULARITY.x; WorldBounds.mMin.y = rmt::Floor(WorldBounds.mMin.y/TODO_GRANULARITY.y)*TODO_GRANULARITY.y; WorldBounds.mMin.z = rmt::Floor(WorldBounds.mMin.z/TODO_GRANULARITY.z)*TODO_GRANULARITY.z; StaticTF.Seed( WorldBounds.mMin, 0 ); StaticTF.Seed( WorldBounds.mMax, 0 ); /////////////////////////////////////////////////////////////////////// // TreeFactory: Grow a Tree, damn you! /////////////////////////////////////////////////////////////////////// TODO_GRANULARITY.y = WorldBounds.mMax.y - WorldBounds.mMin.y; StaticTF.Generate( TODO_GRANULARITY ); StaticTF.ExtractTree( &mpStaticTree ); mStaticTreeWalker.SetToRoot( *mpStaticTree );*/ } //////////////////////////////////////////////////////////////////// // TODO: this can be per-function templatized for all member types //////////////////////////////////////////////////////////////////// void WorldScene::PopulateStaticTree() { BoxPts DrawableSP; rmt::Box3D BBox; int i; int max=mStaticTreeWalker.NumNodes(); for(i=0; iGetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.Place( (ISpatialProxyAA&)DrawableSP, mStaticEntities[i] ); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mIntersectElems.Add(ipIntersectDSG); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mIntersectElems.Add(ipIntersectDSG); ipIntersectDSG->mpSpatialNode = pSpatialNode; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( StaticEntityDSG* ipStaticEntity ) { //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipStaticEntity->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.Place( (ISpatialProxyAA&)DrawableSP, mStaticEntities[i] ); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); if(! pSpatialNode->mSEntityElems.Add(ipStaticEntity)) { pSpatialNode = &(mStaticTreeWalker.rIthNode(0)); if( ! pSpatialNode->mSEntityElems.Add(ipStaticEntity) ) { rTuneAssert(false); } else { ipStaticEntity->mpSpatialNode = pSpatialNode; } } else { ipStaticEntity->mpSpatialNode = pSpatialNode; } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( StaticPhysDSG* ipStaticPhys ) { //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipStaticPhys->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.Place( (ISpatialProxyAA&)DrawableSP, mStaticEntities[i] ); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mSPhysElems.Add(ipStaticPhys); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mSPhysElems.Add(ipStaticPhys); ipStaticPhys->mpSpatialNode = pSpatialNode; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( DynaPhysDSG* ipDynaPhys ) { //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipDynaPhys->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); if(! pSpatialNode->mDPhysElems.Add(ipDynaPhys)) { pSpatialNode = &(mStaticTreeWalker.rIthNode(0)); if( ! pSpatialNode->mDPhysElems.Add(ipDynaPhys) ) { rTuneAssert(false); } else { ipDynaPhys->mpSpatialNode = pSpatialNode; } } else { ipDynaPhys->mpSpatialNode = pSpatialNode; } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( FenceEntityDSG* ipFence ) { //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipFence->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mFenceElems.Add(ipFence); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mFenceElems.Add(ipFence); ipFence->mpSpatialNode = pSpatialNode; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( AnimCollisionEntityDSG* ipAnimColl ) { //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipAnimColl->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); if(! pSpatialNode->mAnimCollElems.Add(ipAnimColl)) { pSpatialNode = &(mStaticTreeWalker.rIthNode(0)); if( ! pSpatialNode->mAnimCollElems.Add(ipAnimColl) ) { rTuneAssert(false); } else { ipAnimColl->mpSpatialNode = pSpatialNode; } } else { ipAnimColl->mpSpatialNode = pSpatialNode; } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( AnimEntityDSG* ipAnim ) { // if( ipAnim->GetUID() == tName::MakeUID("smokecolumn") ) // rReleasePrintf("hjeifjijf"); //rAssert(false); //This currently fails because PopulateStaticTree doesn't //reserve any extra places for stuff to be added BoxPts DrawableSP; rmt::Box3D BBox; ipAnim->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); if(! pSpatialNode->mAnimElems.Add(ipAnim)) { pSpatialNode = &(mStaticTreeWalker.rIthNode(0)); if( ! pSpatialNode->mAnimElems.Add(ipAnim) ) { rTuneAssert(false); } else { ipAnim->mpSpatialNode = pSpatialNode; } } else { ipAnim->mpSpatialNode = pSpatialNode; } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( TriggerVolume* ipTriggerVolume ) { BoxPts DrawableSP; rmt::Box3D BBox; ipTriggerVolume->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mTrigVolElems.Add(ipTriggerVolume); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mTrigVolElems.Add(ipTriggerVolume); ipTriggerVolume->mpSpatialNode = pSpatialNode; } //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( RoadSegment* ipRoadSegment ) { BoxPts DrawableSP; rmt::Box3D BBox; ipRoadSegment->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mRoadSegmentElems.Add(ipRoadSegment); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mRoadSegmentElems.Add(ipRoadSegment); ipRoadSegment->mpSpatialNode = pSpatialNode; } //////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldScene::Place( PathSegment* ipPathSegment ) { BoxPts DrawableSP; rmt::Box3D BBox; ipPathSegment->GetBoundingBox( &BBox ); DrawableSP.mBounds.mMin.SetTo( BBox.low ); DrawableSP.mBounds.mMax.SetTo( BBox.high ); DrawableSP.mBounds.mMin.Add(mEpsilonOffset); DrawableSP.mBounds.mMax.Sub(mEpsilonOffset); //mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP).mPathSegmentElems.Add(ipPathSegment); SpatialNode* pSpatialNode = &(mStaticTreeWalker.rSeekNode((ISpatialProxyAA&)DrawableSP)); pSpatialNode->mPathSegmentElems.Add(ipPathSegment); ipPathSegment->mpSpatialNode = pSpatialNode; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// bool WorldScene::IsPreTreeGen() { if( mpStaticTree == NULL ) return true; else return false; } //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// bool WorldScene::IsPostTreeGen() { if( mpStaticTree == NULL ) return false; else return true; } #include #include //////////////////////////////////////////////////////////////////// // TODO: Move this type of functionality elsewhere // I think WorldScene Should just maintain the data interfaces // and management, not state of said data nor manipulation // thereof /////////////////////////////////////////////////////////////////// //static tShader* spDefaultShader = NULL; void WorldScene::MarkCameraVisible( tPointCamera* pCam, unsigned int iFilter ) { //HexahedronP ViewVolSP; #if 1 SphereSP ViewVolSP; Vector3f CamPosn, ViewVector, FarPlaneExtentVect; pCam->GetPosition(&CamPosn); pCam->GetTarget(&ViewVector); ViewVector.Sub( CamPosn ); ViewVector.Normalize(); SetVisCone( ViewVector, CamPosn, pCam->GetFieldOfView()/1.87f );//this tweak was done to account for the pop-in along the diagonal, especially evident in the interiors//0.8726645f ); // 50 degrees 1.745329f ); //100 degrees ViewVector.Mult( mDrawDist / 2.0f ); ViewVector.Add( CamPosn ); ViewVolSP.SetTo( ViewVector, mDrawDist / 2.0f ); //comment this out //if(spDefaultShader==NULL) // spDefaultShader = new tShader("simple"); //P3DDrawSphere(ViewVolSP.mRadius,ViewVolSP.mCenter,*spDefaultShader,tColour(255,255,0)); #endif // tPointCamera* pCam = (tPointCamera*)p3d::context->GetView()->GetCamera(); // tPointCamera* pCam = (tPointCamera*)GetSuperCamManager()->GetSCC(0)->GetCamera(); #if 0 rmt::Vector4 WorldPlane; // float WorldPlaneNorm; //Do a hackey box approximation to the frustum, //cuz tCamera doesn't properly provide a decent projection matrix Bounds3f FrustumBBox; Vector3f CamPosn, ViewVector, FarPlaneExtentVect; pCam->GetPosition(&CamPosn); pCam->GetTarget(&ViewVector); ViewVector.Sub( CamPosn ); ViewVector.Normalize(); //ViewVector.Mult( 200.0f ); FarPlaneExtentVect.CrossProduct(ViewVector,rmt::Vector(0.0f,1.0f,0.0f)); FarPlaneExtentVect.Mult( mDrawDist ); //200 //ViewVector.Mult(7.0f); // ViewVector.Mult(16.0f); cut back for new art //ViewVector.Mult(4.0f); ViewVector.Mult(mDrawDist); FrustumBBox.mMin = CamPosn; FrustumBBox.mMin.y -= 10.0f; FrustumBBox.mMax = CamPosn; FrustumBBox.Accumulate( CamPosn.x + ViewVector.x + FarPlaneExtentVect.x, CamPosn.y + ViewVector.y + FarPlaneExtentVect.y, CamPosn.z + ViewVector.z + FarPlaneExtentVect.z ); FrustumBBox.Accumulate( CamPosn.x + ViewVector.x - FarPlaneExtentVect.x, CamPosn.y + ViewVector.y - FarPlaneExtentVect.y, CamPosn.z + ViewVector.z - FarPlaneExtentVect.z ); ViewVolSP.SetPlane( HexahedronP::msBack, 0.0f, -1.0f, 0.0f, FrustumBBox.mMin.y); ViewVolSP.SetPlane( HexahedronP::msFront, 0.0f, 1.0f, 0.0f, (-1.0f)*FrustumBBox.mMax.y); ViewVolSP.SetPlane( HexahedronP::msLeft, -1.0f, 0.0f, 0.0f, FrustumBBox.mMin.x); ViewVolSP.SetPlane( HexahedronP::msRight, 1.0f, 0.0f, 0.0f, (-1.0f)*FrustumBBox.mMax.x); ViewVolSP.SetPlane( HexahedronP::msTop, 0.0f, 0.0f, -1.0f, FrustumBBox.mMin.z); ViewVolSP.SetPlane( HexahedronP::msBottom, 0.0f, 0.0f, 1.0f, (-1.0f)*FrustumBBox.mMax.z); //#else // ViewVector.Mult(16.0f); cut back for new art float tmpFar = pCam->GetFarPlane(); pCam->SetFarPlane(mDrawDist); //pCam->SetFarPlane(175.0f); BuildFrustumPlanes( pCam, mCamPlanes ); pCam->SetFarPlane(tmpFar); ViewVolSP.SetPlane( HexahedronP::msTop, mCamPlanes[0].x, mCamPlanes[0].y, mCamPlanes[0].z, mCamPlanes[0].w ); ViewVolSP.SetPlane( HexahedronP::msLeft, mCamPlanes[1].x, mCamPlanes[1].y, mCamPlanes[1].z, mCamPlanes[1].w ); ViewVolSP.SetPlane( HexahedronP::msBottom, mCamPlanes[2].x, mCamPlanes[2].y, mCamPlanes[2].z, mCamPlanes[2].w ); ViewVolSP.SetPlane( HexahedronP::msRight, mCamPlanes[3].x, mCamPlanes[3].y, mCamPlanes[3].z, mCamPlanes[3].w ); ViewVolSP.SetPlane( HexahedronP::msBack, mCamPlanes[4].x, mCamPlanes[4].y, mCamPlanes[4].z, mCamPlanes[4].w ); ViewVolSP.SetPlane( HexahedronP::msFront, mCamPlanes[5].x, mCamPlanes[5].y, mCamPlanes[5].z, mCamPlanes[5].w ); #endif //ViewVolSP.GeneratePoints(); //mStaticTreeWalker.MarkAll( ViewVolSP, iFilter ); mStaticTreeWalker.MarkAllSphere( ViewVolSP, iFilter ); } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// void WorldScene::BuildFrustumPlanes( tPointCamera* pCam, FixedArray& orCamPlanes ) { rAssert( orCamPlanes.mSize == 6 ); // tPointCamera* pCam = (tPointCamera*)p3d::context->GetView()->GetCamera(); // tPointCamera* pCam = (tPointCamera*)GetSuperCamManager()->GetSCC(0)->GetCamera(); const rmt::Matrix* pCam2WorldMat = &pCam->GetCameraToWorldMatrix(); // // Build the camera volume (written by Nigel Brooke) // // Plane cameraPlanes[6]; // camera parameters float fov, aspect; pCam->GetFOV( &fov, &aspect ); //fov = fov/1.5f; //float aspect = 1.333f; // TODO : shouldn't be hardcoded float nearPlane = pCam->GetNearPlane(); float farPlane = pCam->GetFarPlane(); // build some useful points rmt::Vector eye = pCam2WorldMat->Row(3); // eye point rmt::Vector look = pCam2WorldMat->Row(2); // look direciton, normal for far plane rmt::Vector toFarPlane = look; toFarPlane.Scale(farPlane); rmt::Vector onFarPlane = eye; onFarPlane.Add(toFarPlane); // a point on the far plane rmt::Vector lookInv = pCam2WorldMat->Row(2); lookInv.Scale(-1); // toNearPlane offset by a small value to avoid some artifacts rmt::Vector toNearPlane = look; toNearPlane.Scale(nearPlane - 0.00001f); rmt::Vector onNearPlane = eye; onNearPlane.Add(toNearPlane); // find surface normals for left and right clipping pplanes // first get camera space vectors rmt::Vector tmpr(rmt::Cos(fov/2), 0, -rmt::Sin(fov/2)); // right vector is 'rotated' by fov/2 rmt::Vector tmpl = tmpr; tmpl.Scale(-1,1,1); // left vector is inverse of right // then pass points through camera matrix to get world space vectors rmt::Vector right, left; pCam2WorldMat->RotateVector(tmpr, &right); pCam2WorldMat->RotateVector(tmpl, &left); // find surface normals for top and bottom clipping planes, just like left and right // get camera space vectors rmt::Vector tmpu(0, rmt::Cos(fov/2), -rmt::Sin(fov/2)); tmpu.Scale(1, aspect, 1); tmpu.Normalize(); rmt::Vector tmpd = tmpu; tmpd.Scale(1,-1,1); // tranform to worldspace rmt::Vector up, down; pCam2WorldMat->RotateVector(tmpu, &up); pCam2WorldMat->RotateVector(tmpd, &down); // set the planes using point in plane and normal format // 'eye' is on all clipping planes except far and near orCamPlanes[0].Set(up.x, up.y, up.z, -up.DotProduct(eye)); orCamPlanes[1].Set(left.x, left.y, left.z, -left.DotProduct(eye)); orCamPlanes[2].Set(down.x, down.y, down.z, -down.DotProduct(eye)); orCamPlanes[3].Set(right.x, right.y, right.z, -right.DotProduct(eye)); orCamPlanes[4].Set(look.x, look.y, look.z, -look.DotProduct(onFarPlane)); orCamPlanes[5].Set(lookInv.x, lookInv.y, lookInv.z, -lookInv.DotProduct(onNearPlane)); }