sceneManager.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "scene/sceneManager.h"
  24. #include "scene/sceneObject.h"
  25. #include "scene/zones/sceneTraversalState.h"
  26. #include "scene/sceneRenderState.h"
  27. #include "scene/zones/sceneRootZone.h"
  28. #include "scene/zones/sceneZoneSpace.h"
  29. #include "lighting/lightManager.h"
  30. #include "renderInstance/renderPassManager.h"
  31. #include "gfx/gfxDevice.h"
  32. #include "gfx/gfxDrawUtil.h"
  33. #include "gfx/gfxDebugEvent.h"
  34. #include "console/engineAPI.h"
  35. #include "sim/netConnection.h"
  36. #include "T3D/gameBase/gameConnection.h"
  37. #include "math/mathUtils.h"
  38. #include "T3D/components/render/renderComponentInterface.h"
  39. #include "T3D/systems/render/meshRenderSystem.h"
  40. // For player object bounds workaround.
  41. #include "T3D/player.h"
  42. #include "postFx/postEffectManager.h"
  43. extern bool gEditingMission;
  44. MODULE_BEGIN( Scene )
  45. MODULE_INIT_AFTER( Sim )
  46. MODULE_SHUTDOWN_BEFORE( Sim )
  47. MODULE_INIT
  48. {
  49. // Client scene.
  50. gClientSceneGraph = new SceneManager( true );
  51. // Server scene.
  52. gServerSceneGraph = new SceneManager( false );
  53. Con::addVariable( "$Scene::lockCull", TypeBool, &SceneManager::smLockDiffuseFrustum,
  54. "Debug tool which locks the frustum culling to the current camera location.\n"
  55. "@ingroup Rendering\n" );
  56. Con::addVariable( "$Scene::disableTerrainOcclusion", TypeBool, &SceneCullingState::smDisableTerrainOcclusion,
  57. "Used to disable the somewhat expensive terrain occlusion testing.\n"
  58. "@ingroup Rendering\n" );
  59. Con::addVariable( "$Scene::disableZoneCulling", TypeBool, &SceneCullingState::smDisableZoneCulling,
  60. "If true, zone culling will be disabled and the scene contents will only be culled against the root frustum.\n\n"
  61. "@ingroup Rendering\n" );
  62. Con::addVariable( "$Scene::renderBoundingBoxes", TypeBool, &SceneManager::smRenderBoundingBoxes,
  63. "If true, the bounding boxes of objects will be displayed.\n\n"
  64. "@ingroup Rendering" );
  65. Con::addVariable( "$Scene::maxOccludersPerZone", TypeS32, &SceneCullingState::smMaxOccludersPerZone,
  66. "Maximum number of occluders that will be concurrently allowed into the scene culling state of any given zone.\n\n"
  67. "@ingroup Rendering" );
  68. Con::addVariable( "$Scene::occluderMinWidthPercentage", TypeF32, &SceneCullingState::smOccluderMinWidthPercentage,
  69. "TODO\n\n"
  70. "@ingroup Rendering" );
  71. Con::addVariable( "$Scene::occluderMinHeightPercentage", TypeF32, &SceneCullingState::smOccluderMinHeightPercentage,
  72. "TODO\n\n"
  73. "@ingroup Rendering" );
  74. }
  75. MODULE_SHUTDOWN
  76. {
  77. SAFE_DELETE( gClientSceneGraph );
  78. SAFE_DELETE( gServerSceneGraph );
  79. }
  80. MODULE_END;
  81. bool SceneManager::smRenderBoundingBoxes;
  82. bool SceneManager::smLockDiffuseFrustum = false;
  83. SceneCameraState SceneManager::smLockedDiffuseCamera = SceneCameraState( RectI(), Frustum(), MatrixF(), MatrixF() );
  84. SceneManager* gClientSceneGraph = NULL;
  85. SceneManager* gServerSceneGraph = NULL;
  86. //-----------------------------------------------------------------------------
  87. SceneManager::SceneManager( bool isClient )
  88. : mIsClient( isClient ),
  89. mZoneManager( NULL ),
  90. mUsePostEffectFog( true ),
  91. mDisplayTargetResolution( 0, 0 ),
  92. mCurrentRenderState( NULL ),
  93. mVisibleDistance( 500.f ),
  94. mVisibleGhostDistance( 0 ),
  95. mNearClip( 0.1f ),
  96. mLightManager( NULL ),
  97. mAmbientLightColor( LinearColorF( 0.1f, 0.1f, 0.1f, 1.0f ) ),
  98. mDefaultRenderPass( NULL )
  99. {
  100. VECTOR_SET_ASSOCIATION( mBatchQueryList );
  101. // For the client, create a zone manager.
  102. if( isClient )
  103. {
  104. mZoneManager = new SceneZoneSpaceManager( getContainer() );
  105. // Add the root zone to the scene.
  106. addObjectToScene( mZoneManager->getRootZone() );
  107. }
  108. }
  109. //-----------------------------------------------------------------------------
  110. SceneManager::~SceneManager()
  111. {
  112. SAFE_DELETE( mZoneManager );
  113. if( mLightManager )
  114. mLightManager->deactivate();
  115. }
  116. //-----------------------------------------------------------------------------
  117. void SceneManager::renderScene( ScenePassType passType, U32 objectMask )
  118. {
  119. SceneCameraState cameraState = SceneCameraState::fromGFX();
  120. // Handle frustum locking.
  121. const bool lockedFrustum = ( smLockDiffuseFrustum && passType == SPT_Diffuse );
  122. if( lockedFrustum )
  123. cameraState = smLockedDiffuseCamera;
  124. else if( passType == SPT_Diffuse )
  125. {
  126. // Store the camera state so if we lock, this will become the
  127. // locked state.
  128. smLockedDiffuseCamera = cameraState;
  129. }
  130. // Create the render state.
  131. SceneRenderState renderState( this, passType, cameraState );
  132. // If we have locked the frustum, reset the view transform
  133. // on the render pass which the render state has just set
  134. // to the view matrix corresponding to the locked frustum. For
  135. // rendering, however, we need the true view matrix from the
  136. // GFX state.
  137. if( lockedFrustum )
  138. {
  139. RenderPassManager* rpm = renderState.getRenderPass();
  140. rpm->assignSharedXform( RenderPassManager::View, GFX->getWorldMatrix() );
  141. }
  142. // Render.
  143. renderScene( &renderState, objectMask );
  144. }
  145. //-----------------------------------------------------------------------------
  146. void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone )
  147. {
  148. PROFILE_SCOPE( SceneGraph_renderScene );
  149. // Get the lights for rendering the scene.
  150. PROFILE_START( SceneGraph_registerLights );
  151. LIGHTMGR->registerGlobalLights( &renderState->getCullingFrustum(), false );
  152. PROFILE_END();
  153. // If its a diffuse pass, update the current ambient light level.
  154. // To do that find the starting zone and determine whether it has a custom
  155. // ambient light color. If so, pass it on to the ambient light manager.
  156. // If not, use the ambient light color of the sunlight.
  157. //
  158. // Note that we retain the starting zone information here and pass it
  159. // on to renderSceneNoLights so that we don't need to look it up twice.
  160. if( renderState->isDiffusePass() )
  161. {
  162. if( !baseObject && getZoneManager() )
  163. {
  164. getZoneManager()->findZone( renderState->getCameraPosition(), baseObject, baseZone );
  165. AssertFatal( baseObject != NULL, "SceneManager::renderScene - findZone() did not return an object" );
  166. }
  167. LinearColorF zoneAmbient;
  168. if( baseObject && baseObject->getZoneAmbientLightColor( baseZone, zoneAmbient ) )
  169. mAmbientLightColor.setTargetValue( zoneAmbient );
  170. else
  171. {
  172. const LightInfo* sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
  173. if( sunlight )
  174. mAmbientLightColor.setTargetValue( sunlight->getAmbient() );
  175. }
  176. renderState->setAmbientLightColor( mAmbientLightColor.getCurrentValue() );
  177. }
  178. // Trigger the pre-render signal.
  179. PROFILE_START( SceneGraph_preRenderSignal);
  180. mCurrentRenderState = renderState;
  181. getPreRenderSignal().trigger( this, renderState );
  182. mCurrentRenderState = NULL;
  183. PROFILE_END();
  184. // Render the scene.
  185. if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide)
  186. {
  187. // Store previous values
  188. RectI originalVP = GFX->getViewport();
  189. MatrixF originalWorld = GFX->getWorldMatrix();
  190. Frustum originalFrustum = GFX->getFrustum();
  191. // Save PFX & SceneManager projections
  192. MatrixF origNonClipProjection = renderState->getSceneManager()->getNonClipProjection();
  193. PFXFrameState origPFXState = PFXMGR->getFrameState();
  194. const FovPort *currentFovPort = GFX->getStereoFovPort();
  195. const MatrixF *worldEyeTransforms = GFX->getInverseStereoEyeTransforms();
  196. // Render left half of display
  197. GFX->activateStereoTarget(0);
  198. GFX->beginField();
  199. GFX->setWorldMatrix(worldEyeTransforms[0]);
  200. Frustum gfxFrustum = originalFrustum;
  201. MathUtils::makeFovPortFrustum(&gfxFrustum, gfxFrustum.isOrtho(), gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[0]);
  202. GFX->setFrustum(gfxFrustum);
  203. SceneCameraState cameraStateLeft = SceneCameraState::fromGFX();
  204. SceneRenderState renderStateLeft( this, renderState->getScenePassType(), cameraStateLeft );
  205. renderStateLeft.getSceneManager()->setNonClipProjection(GFX->getProjectionMatrix());
  206. renderStateLeft.setSceneRenderStyle(SRS_SideBySide);
  207. PFXMGR->setFrameMatrices(GFX->getWorldMatrix(), GFX->getProjectionMatrix());
  208. renderSceneNoLights( &renderStateLeft, objectMask, baseObject, baseZone ); // left
  209. // Indicate that we've just finished a field
  210. //GFX->clear(GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI(255,0,0), 1.0f, 0);
  211. GFX->endField();
  212. // Render right half of display
  213. GFX->activateStereoTarget(1);
  214. GFX->beginField();
  215. GFX->setWorldMatrix(worldEyeTransforms[1]);
  216. gfxFrustum = originalFrustum;
  217. MathUtils::makeFovPortFrustum(&gfxFrustum, gfxFrustum.isOrtho(), gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[1]);
  218. GFX->setFrustum(gfxFrustum);
  219. SceneCameraState cameraStateRight = SceneCameraState::fromGFX();
  220. SceneRenderState renderStateRight( this, renderState->getScenePassType(), cameraStateRight );
  221. renderStateRight.getSceneManager()->setNonClipProjection(GFX->getProjectionMatrix());
  222. renderStateRight.setSceneRenderStyle(SRS_SideBySide);
  223. PFXMGR->setFrameMatrices(GFX->getWorldMatrix(), GFX->getProjectionMatrix());
  224. renderSceneNoLights( &renderStateRight, objectMask, baseObject, baseZone ); // right
  225. // Indicate that we've just finished a field
  226. //GFX->clear(GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI(0,255,0), 1.0f, 0);
  227. GFX->endField();
  228. // Restore previous values
  229. renderState->getSceneManager()->setNonClipProjection(origNonClipProjection);
  230. PFXMGR->setFrameState(origPFXState);
  231. GFX->setWorldMatrix(originalWorld);
  232. GFX->setFrustum(originalFrustum);
  233. GFX->setViewport(originalVP);
  234. }
  235. else
  236. {
  237. renderSceneNoLights( renderState, objectMask, baseObject, baseZone );
  238. }
  239. // Trigger the post-render signal.
  240. PROFILE_START( SceneGraphRender_postRenderSignal );
  241. mCurrentRenderState = renderState;
  242. getPostRenderSignal().trigger( this, renderState );
  243. mCurrentRenderState = NULL;
  244. PROFILE_END();
  245. // Remove the previously registered lights.
  246. PROFILE_START( SceneGraph_unregisterLights);
  247. LIGHTMGR->unregisterAllLights();
  248. PROFILE_END();
  249. }
  250. //-----------------------------------------------------------------------------
  251. void SceneManager::renderSceneNoLights( SceneRenderState* renderState, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone )
  252. {
  253. // Set the current state.
  254. mCurrentRenderState = renderState;
  255. // Render.
  256. _renderScene( mCurrentRenderState, objectMask, baseObject, baseZone );
  257. #ifdef TORQUE_DEBUG
  258. // If frustum is locked and this is a diffuse pass, render the culling volumes of
  259. // zones that are selected (or the volumes of the outdoor zone if no zone is
  260. // selected).
  261. if( gEditingMission && renderState->isDiffusePass() && smLockDiffuseFrustum )
  262. renderState->getCullingState().debugRenderCullingVolumes();
  263. #endif
  264. mCurrentRenderState = NULL;
  265. }
  266. //-----------------------------------------------------------------------------
  267. void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone )
  268. {
  269. AssertFatal( this == gClientSceneGraph, "SceneManager::_buildSceneGraph - Only the client scenegraph can support this call!" );
  270. PROFILE_SCOPE( SceneGraph_batchRenderImages );
  271. // In the editor, override the type mask for diffuse passes.
  272. if( gEditingMission && state->isDiffusePass() )
  273. objectMask = EDITOR_RENDER_TYPEMASK;
  274. MeshRenderSystem::render(this, state);
  275. // Update the zoning state and traverse zones.
  276. if( getZoneManager() )
  277. {
  278. // Update.
  279. getZoneManager()->updateZoningState();
  280. // If zone culling isn't disabled, traverse the
  281. // zones now.
  282. if( !state->getCullingState().disableZoneCulling() )
  283. {
  284. // Find the start zone if we haven't already.
  285. if( !baseObject )
  286. {
  287. getZoneManager()->findZone( state->getCameraPosition(), baseObject, baseZone );
  288. AssertFatal( baseObject != NULL, "SceneManager::_renderScene - findZone() did not return an object" );
  289. }
  290. // Traverse zones starting in base object.
  291. SceneTraversalState traversalState( &state->getCullingState() );
  292. PROFILE_START( Scene_traverseZones );
  293. baseObject->traverseZones( &traversalState, baseZone );
  294. PROFILE_END();
  295. // Set the scene render box to the area we have traversed.
  296. state->setRenderArea( traversalState.getTraversedArea() );
  297. }
  298. }
  299. // Set the query box for the container query. Never
  300. // make it larger than the frustum's AABB. In the editor,
  301. // always query the full frustum as that gives objects
  302. // the opportunity to render editor visualizations even if
  303. // they are otherwise not in view.
  304. if( !state->getCullingFrustum().getBounds().isOverlapped( state->getRenderArea() ) )
  305. {
  306. // This handles fringe cases like flying backwards into a zone where you
  307. // end up pretty much standing on a zone border and looking directly into
  308. // its "walls". In that case the traversal area will be behind the frustum
  309. // (remember that the camera isn't where visibility starts, it's the near
  310. // distance).
  311. return;
  312. }
  313. Box3F queryBox = state->getCullingFrustum().getBounds();
  314. if( !gEditingMission )
  315. {
  316. queryBox.minExtents.setMax( state->getRenderArea().minExtents );
  317. queryBox.maxExtents.setMin( state->getRenderArea().maxExtents );
  318. }
  319. PROFILE_START( Scene_cullObjects );
  320. //TODO: We should split the codepaths here based on whether the outdoor zone has visible space.
  321. // If it has, we should use the container query-based path.
  322. // If it hasn't, we should fill the object list directly from the zone lists which will usually
  323. // include way fewer objects.
  324. // Gather all objects that intersect the scene render box.
  325. mBatchQueryList.clear();
  326. getContainer()->findObjectList( queryBox, objectMask, &mBatchQueryList );
  327. // Cull the list.
  328. U32 numRenderObjects = state->getCullingState().cullObjects(
  329. mBatchQueryList.address(),
  330. mBatchQueryList.size(),
  331. !state->isDiffusePass() ? SceneCullingState::CullEditorOverrides : 0 // Keep forced editor stuff out of non-diffuse passes.
  332. );
  333. //HACK: If the control object is a Player and it is not in the render list, force
  334. // it into it. This really should be solved by collision bounds being separate from
  335. // object bounds; only because the Player class is using bounds not encompassing
  336. // the actual player object is it that we have this problem in the first place.
  337. // Note that we are forcing the player object into ALL passes here but such
  338. // is the power of proliferation of things done wrong.
  339. GameConnection* connection = GameConnection::getConnectionToServer();
  340. if( connection )
  341. {
  342. Player* player = dynamic_cast< Player* >( connection->getControlObject() );
  343. if( player )
  344. {
  345. mBatchQueryList.setSize( numRenderObjects );
  346. if( !mBatchQueryList.contains( player ) )
  347. {
  348. mBatchQueryList.push_back( player );
  349. numRenderObjects ++;
  350. }
  351. }
  352. }
  353. PROFILE_END();
  354. //store our rendered objects into a list we can easily look up against later if required
  355. mRenderedObjectsList.clear();
  356. for (U32 i = 0; i < numRenderObjects; ++i)
  357. {
  358. mRenderedObjectsList.push_back(mBatchQueryList[i]);
  359. }
  360. // Render the remaining objects.
  361. PROFILE_START( Scene_renderObjects );
  362. state->renderObjects( mBatchQueryList.address(), numRenderObjects );
  363. PROFILE_END();
  364. // Render bounding boxes, if enabled.
  365. if( smRenderBoundingBoxes && state->isDiffusePass() )
  366. {
  367. GFXDEBUGEVENT_SCOPE( Scene_renderBoundingBoxes, ColorI::WHITE );
  368. GameBase* cameraObject = 0;
  369. if( connection )
  370. cameraObject = connection->getCameraObject();
  371. GFXStateBlockDesc desc;
  372. desc.setFillModeWireframe();
  373. desc.setZReadWrite( true, false );
  374. for( U32 i = 0; i < numRenderObjects; ++ i )
  375. {
  376. SceneObject* object = mBatchQueryList[ i ];
  377. // Skip global bounds object.
  378. if( object->isGlobalBounds() )
  379. continue;
  380. // Skip camera object as we're viewing the scene from it.
  381. if( object == cameraObject )
  382. continue;
  383. const Box3F& worldBox = object->getWorldBox();
  384. GFX->getDrawUtil()->drawObjectBox(
  385. desc,
  386. Point3F( worldBox.len_x(), worldBox.len_y(), worldBox.len_z() ),
  387. worldBox.getCenter(),
  388. MatrixF::Identity,
  389. ColorI::WHITE
  390. );
  391. }
  392. }
  393. }
  394. //-----------------------------------------------------------------------------
  395. struct ScopingInfo
  396. {
  397. Point3F scopePoint;
  398. F32 scopeDist;
  399. F32 scopeDistSquared;
  400. NetConnection* connection;
  401. };
  402. static void _scopeCallback( SceneObject* object, void* data )
  403. {
  404. if( !object->isScopeable() )
  405. return;
  406. ScopingInfo* info = reinterpret_cast< ScopingInfo* >( data );
  407. NetConnection* connection = info->connection;
  408. F32 difSq = ( object->getWorldSphere().center - info->scopePoint ).lenSquared();
  409. if( difSq < info->scopeDistSquared )
  410. {
  411. // Not even close, it's in...
  412. connection->objectInScope( object );
  413. }
  414. else
  415. {
  416. // Check a little more closely...
  417. F32 realDif = mSqrt( difSq );
  418. if( realDif - object->getWorldSphere().radius < info->scopeDist)
  419. connection->objectInScope( object );
  420. }
  421. }
  422. void SceneManager::scopeScene( CameraScopeQuery* query, NetConnection* netConnection )
  423. {
  424. PROFILE_SCOPE( SceneGraph_scopeScene );
  425. // Note that this method does not use the zoning information in the scene
  426. // to scope objects. The reason is that with the way that scoping is implemented
  427. // in the networking layer--i.e. by killing off ghosts of objects that are out
  428. // of scope--, it doesn't make sense to let, for example, all objects in the outdoor
  429. // zone go out of scope, just because there is no exterior portal that is visible from
  430. // the current camera viewpoint (in any direction).
  431. //
  432. // So, we perform a simple box query on the area covered by the camera query
  433. // and then scope in everything that is in range.
  434. // Set up scoping info.
  435. ScopingInfo info;
  436. info.scopePoint = query->pos;
  437. info.scopeDist = query->visibleDistance;
  438. info.scopeDistSquared = info.scopeDist * info.scopeDist;
  439. info.connection = netConnection;
  440. // Scope all objects in the query area.
  441. Box3F area( query->visibleDistance );
  442. area.setCenter( query->pos );
  443. getContainer()->findObjects( area, 0xFFFFFFFF, _scopeCallback, &info );
  444. }
  445. //-----------------------------------------------------------------------------
  446. bool SceneManager::addObjectToScene( SceneObject* object )
  447. {
  448. AssertFatal( !object->mSceneManager, "SceneManager::addObjectToScene - Object already part of a scene" );
  449. // Mark the object as belonging to us.
  450. object->mSceneManager = this;
  451. // Register with managers except its the root zone.
  452. if( !dynamic_cast< SceneRootZone* >( object ) )
  453. {
  454. // Add to container.
  455. getContainer()->addObject( object );
  456. // Register the object with the zone manager.
  457. if( getZoneManager() )
  458. getZoneManager()->registerObject( object );
  459. }
  460. // Notify the object.
  461. return object->onSceneAdd();
  462. }
  463. //-----------------------------------------------------------------------------
  464. void SceneManager::removeObjectFromScene( SceneObject* obj )
  465. {
  466. AssertFatal( obj, "SceneManager::removeObjectFromScene - Object is not declared" );
  467. AssertFatal( obj->getSceneManager() == this, "SceneManager::removeObjectFromScene - Object not part of SceneManager" );
  468. // Notify the object.
  469. obj->onSceneRemove();
  470. // Remove the object from the container.
  471. if( getContainer() )
  472. getContainer()->removeObject( obj );
  473. // Remove the object from the zoning system.
  474. if( getZoneManager() )
  475. getZoneManager()->unregisterObject( obj );
  476. // Clear out the reference to us.
  477. obj->mSceneManager = NULL;
  478. }
  479. //-----------------------------------------------------------------------------
  480. void SceneManager::notifyObjectDirty( SceneObject* object )
  481. {
  482. // Update container state.
  483. if( object->mContainer )
  484. object->mContainer->checkBins( object );
  485. // Mark zoning state as dirty.
  486. if( getZoneManager() )
  487. getZoneManager()->notifyObjectChanged( object );
  488. }
  489. //-----------------------------------------------------------------------------
  490. void SceneManager::setDisplayTargetResolution( const Point2I &size )
  491. {
  492. mDisplayTargetResolution = size;
  493. }
  494. //-----------------------------------------------------------------------------
  495. const Point2I & SceneManager::getDisplayTargetResolution() const
  496. {
  497. return mDisplayTargetResolution;
  498. }
  499. //-----------------------------------------------------------------------------
  500. bool SceneManager::setLightManager( const char* lmName )
  501. {
  502. LightManager *lm = LightManager::findByName( lmName );
  503. if ( !lm )
  504. return false;
  505. return _setLightManager( lm );
  506. }
  507. //-----------------------------------------------------------------------------
  508. bool SceneManager::_setLightManager( LightManager* lm )
  509. {
  510. // Avoid unnecessary work reinitializing materials.
  511. if ( lm == mLightManager )
  512. return true;
  513. // Make sure its valid... else fail!
  514. if ( !lm->isCompatible() )
  515. return false;
  516. // We only deactivate it... all light managers are singletons
  517. // and will manager their own lifetime.
  518. if ( mLightManager )
  519. mLightManager->deactivate();
  520. mLightManager = lm;
  521. if ( mLightManager )
  522. mLightManager->activate( this );
  523. return true;
  524. }
  525. //-----------------------------------------------------------------------------
  526. RenderPassManager* SceneManager::getDefaultRenderPass() const
  527. {
  528. if( !mDefaultRenderPass )
  529. {
  530. Sim::findObject( "DiffuseRenderPassManager", mDefaultRenderPass );
  531. AssertISV( mDefaultRenderPass, "SceneManager::_setDefaultRenderPass - No DiffuseRenderPassManager defined! Must be set up in script!" );
  532. }
  533. return mDefaultRenderPass;
  534. }
  535. //=============================================================================
  536. // Console API.
  537. //=============================================================================
  538. // MARK: ---- Console API ----
  539. //-----------------------------------------------------------------------------
  540. DefineEngineFunction( sceneDumpZoneStates, void, ( bool updateFirst ), ( true ),
  541. "Dump the current zoning states of all zone spaces in the scene to the console.\n\n"
  542. "@param updateFirst If true, zoning states are brought up to date first; if false, the zoning states "
  543. "are dumped as is.\n\n"
  544. "@note Only valid on the client.\n"
  545. "@ingroup Game" )
  546. {
  547. if( !gClientSceneGraph )
  548. {
  549. Con::errorf( "sceneDumpZoneStates - Only valid on client!" );
  550. return;
  551. }
  552. SceneZoneSpaceManager* manager = gClientSceneGraph->getZoneManager();
  553. if( !manager )
  554. {
  555. Con::errorf( "sceneDumpZoneStates - Scene is not using zones!" );
  556. return;
  557. }
  558. manager->dumpZoneStates( updateFirst );
  559. }
  560. //-----------------------------------------------------------------------------
  561. DefineEngineFunction( sceneGetZoneOwner, SceneObject*, ( U32 zoneId ),,
  562. "Return the SceneObject that contains the given zone.\n\n"
  563. "@param zoneId ID of zone.\n"
  564. "@return A SceneObject or NULL if the given @a zoneId is invalid.\n\n"
  565. "@note Only valid on the client.\n"
  566. "@ingroup Game" )
  567. {
  568. if( !gClientSceneGraph )
  569. {
  570. Con::errorf( "sceneGetZoneOwner - Only valid on client!" );
  571. return NULL;
  572. }
  573. SceneZoneSpaceManager* manager = gClientSceneGraph->getZoneManager();
  574. if( !manager )
  575. {
  576. Con::errorf( "sceneGetZoneOwner - Scene is not using zones!" );
  577. return NULL;
  578. }
  579. if( !manager->isValidZoneId( zoneId ) )
  580. {
  581. Con::errorf( "sceneGetZoneOwner - Invalid zone ID: %i", zoneId );
  582. return NULL;
  583. }
  584. return manager->getZoneOwner( zoneId );
  585. }