Torque3D Documentation / _generateds / sceneManager.cpp

sceneManager.cpp

Engine/source/scene/sceneManager.cpp

More...

Classes:

Public Variables

The client-side scene graph.

bool

For frame signal.

The server-side scene graph.

Public Functions

_scopeCallback(SceneObject * object, void * data)
DefineEngineFunction(sceneDumpZoneStates , void , (bool updateFirst) , (true) , "Dump the current zoning states of all zone spaces in the scene <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param updateFirst If true, zoning states are brought up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> date first;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> false, the zoning states " "are dumped as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">is.\n\n</a>" " @note Only valid on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " @ingroup Game" )
DefineEngineFunction(sceneGetZoneOwner , SceneObject * , (U32 zoneId) , "Return the <a href="/coding/class/classsceneobject/">SceneObject</a> that contains the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">zone.\n\n</a>" "@param zoneId ID of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">zone.\n</a>" "@return A <a href="/coding/class/classsceneobject/">SceneObject</a> or <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the given @<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> zoneId is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invalid.\n\n</a>" "@note Only valid on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" "@ingroup Game" )

Detailed Description

Public Variables

SceneManager * gClientSceneGraph 

The client-side scene graph.

Not used if the engine is running as a dedicated server.

bool gEditingMission 

For frame signal.

 gServerSceneGraph 

The server-side scene graph.

Not used if the engine is running as a pure client.

 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 

Public Functions

_scopeCallback(SceneObject * object, void * data)

DefineEngineFunction(sceneDumpZoneStates , void , (bool updateFirst) , (true) , "Dump the current zoning states of all zone spaces in the scene <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param updateFirst If true, zoning states are brought up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> date first;<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> false, the zoning states " "are dumped as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">is.\n\n</a>" " @note Only valid on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " @ingroup Game" )

DefineEngineFunction(sceneGetZoneOwner , SceneObject * , (U32 zoneId) , "Return the <a href="/coding/class/classsceneobject/">SceneObject</a> that contains the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">zone.\n\n</a>" "@param zoneId ID of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">zone.\n</a>" "@return A <a href="/coding/class/classsceneobject/">SceneObject</a> or <a href="/coding/file/typesx86unix_8h/#typesx86unix_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a> <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the given @<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> zoneId is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">invalid.\n\n</a>" "@note Only valid on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" "@ingroup Game" )

SAFE_DELETE(gServerSceneGraph )

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