The-Simpsons-Hit-and-Run/game/code/render/Culling/WorldScene.cpp

2381 lines
81 KiB
C++

#include <render/culling/WorldScene.h>
#include <render/culling/SpatialTreeFactory.h>
#include <render/Culling/SpatialTree.h>
#include <render/Culling/SpatialTreeIter.h>
#include <render/DSG/IntersectDSG.h>
#include <render/DSG/StaticPhysDSG.h>
#include <render/DSG/StaticEntityDSG.h>
#include <render/DSG/DynaPhysDSG.h>
#include <render/DSG/FenceEntityDSG.h>
#include <render/DSG/AnimCollisionEntityDSG.h>
#include <render/DSG/AnimEntityDSG.h>
#include <roads/roadsegment.h>
#include <pedpaths/pathsegment.h>
#include <meta/triggervolume.h>
#include <algorithm>
#include <functional>
#include <render/culling/NodeFLL.h>
#include <render/culling/Matrix3f.h>
#include <camera/supercammanager.h>
#include <raddebugwatch.hpp>
#include <radtime.hpp>
#include <worldsim/worldphysicsmanager.h>
#include <worldsim/avatarmanager.h>
#include <worldsim/avatar.h>
#include <worldsim/redbrick/vehicle.h>
#include <worldsim/character/character.h>
#include <pddi/pdditype.hpp>
#ifdef DEBUGWATCH
#include <simcollision/collisiondisplay.hpp>
#include <simcollision/collisionmanager.hpp>
#include <simcommon/simutility.hpp>
#endif
#ifdef RAD_DEBUG
#include <mission/missionmanager.h>
#include <mission/objectives/missionobjective.h>
#include <meta/triggervolumetracker.h>
#include <gameflow/gameflow.h>
#include <contexts/contextenum.h>
#endif
#include <debug/profiler.h>
#include <stdlib.h>
#ifdef RAD_GAMECUBE
#include <pddi/gamecube/gcrefractionshader.hpp>
#endif
#define TEST_DISTRIBUTED_SORT
#define ZSORT_RENDER
//#define TRACK_SHADERS
//#define TEST_WHOLE_TREE
//For debug section
//#include <render/culling/../debuginfo.hpp"
//#include <render/culling/../../profiler/profiler.hpp"
//For test debugging (camera)
//#include <render/culling/../../main/globals.hpp"
//#include <render/culling/../../main/gamesettings.hpp"
//#include <render/culling/../../worldsim/supercam.hpp"
//#include <render/culling/../../worldsim/player.hpp"
//static Vector3f TODO_GRANULARITY(160.0f, 2000.0f, 160.0f);
//static Vector3f TODO_GRANULARITY(240.0f, 2000.0f, 240.0f);
//static Vector3f TODO_GRANULARITY(10.0f, 2000.0f, 10.0f);
//static Vector3f TODO_GRANULARITY(200.0f, 2000.0f, 200.0f);
#ifdef RAD_GAMECUBE
static Vector3f TODO_GRANULARITY(40.0f, 2000.0f, 40.0f);
#else
static Vector3f TODO_GRANULARITY(20.0f, 2000.0f, 20.0f);
#endif
//static Vector3f TODO_GRANULARITY(120.0f, 2000.0f, 120.0f);
//defines
//#define RENDER_W_DLIST
#ifdef ZSORT_RENDER
// Replace all the following qsort and stl compare functions with stl function objects
struct gZSortCompare: public std::binary_function< IEntityDSG*, IEntityDSG*, bool >
{
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<tShader>("OakL_m");
tTexture* pTexture = p3d::find<tTexture>("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<tShader>("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<IEntityDSG*, s2alloc<IEntityDSG*> > mSort1;
std::vector<IEntityDSG*, s2alloc<IEntityDSG*> > 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<tUID>, 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<StaticPhysDSG*>& 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; i<max; i++)
{
mStaticTreeWalker.rIthNode(i).mSEntityElems.Allocate();
mStaticTreeWalker.rIthNode(i).mSPhysElems.Allocate();
mStaticTreeWalker.rIthNode(i).mIntersectElems.Allocate();
mStaticTreeWalker.rIthNode(i).mDPhysElems.Allocate();
mStaticTreeWalker.rIthNode(i).mFenceElems.Allocate();
mStaticTreeWalker.rIthNode(i).mAnimCollElems.Allocate();
mStaticTreeWalker.rIthNode(i).mAnimElems.Allocate();
mStaticTreeWalker.rIthNode(i).mTrigVolElems.Allocate();
mStaticTreeWalker.rIthNode(i).mRoadSegmentElems.Allocate();
mStaticTreeWalker.rIthNode(i).mPathSegmentElems.Allocate();
}
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//void WorldScene::PlaceStaticGeo( tGeometry* pGeometry )
//{
// rAssert(false);
//This currently fails because PopulateStaticTree doesn't
//reserve any extra places for geo to be added
//}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
void WorldScene::Place( IntersectDSG* ipIntersectDSG )
{
//rAssert(false);
//This currently fails because PopulateStaticTree doesn't
//reserve any extra places for geo to be added
BoxPts DrawableSP;
rmt::Box3D BBox;
ipIntersectDSG->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).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 <render/culling/SphereSP.h>
#include <p3d/debugdraw.hpp>
////////////////////////////////////////////////////////////////////
// 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<rmt::Vector4>& 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));
}