1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Scene/BsSceneManager.h"
4#include "Scene/BsSceneObject.h"
5#include "Scene/BsComponent.h"
6#include "Renderer/BsRenderable.h"
7#include "Renderer/BsCamera.h"
8#include "Renderer/BsLight.h"
9#include "RenderAPI/BsViewport.h"
10#include "Scene/BsGameObjectManager.h"
11#include "RenderAPI/BsRenderTarget.h"
12#include "Renderer/BsLightProbeVolume.h"
13#include "Scene/BsSceneActor.h"
14#include "Scene/BsPrefab.h"
15#include "Physics/BsPhysics.h"
16
17namespace bs
18{
19 enum ListType
20 {
21 NoList = 0,
22 ActiveList = 1,
23 InactiveList = 2,
24 UninitializedList = 3
25 };
26
27 struct ScopeToggle
28 {
29 ScopeToggle(bool& val) :val(val) { val = true; }
30 ~ScopeToggle() { val = false;}
31
32 private:
33 bool& val;
34 };
35
36 SceneInstance::SceneInstance(ConstructPrivately dummy, const String& name, const HSceneObject& root,
37 const SPtr<PhysicsScene>& physicsScene)
38 :mName(name), mRoot(root), mPhysicsScene(physicsScene)
39 { }
40
41 SceneManager::SceneManager()
42 : mMainScene(
43 bs_shared_ptr_new<SceneInstance>(SceneInstance::ConstructPrivately(), "Main",
44 SceneObject::createInternal("SceneRoot"),
45 gPhysics().createPhysicsScene()))
46 {
47 mMainScene->mRoot->setScene(mMainScene);
48 }
49
50 SceneManager::~SceneManager()
51 {
52 mMainScene->mPhysicsScene = nullptr;
53
54 if (mMainScene->mRoot != nullptr && !mMainScene->mRoot.isDestroyed())
55 mMainScene->mRoot->destroy(true);
56 }
57
58 void SceneManager::clearScene(bool forceAll)
59 {
60 UINT32 numChildren = mMainScene->mRoot->getNumChildren();
61
62 UINT32 curIdx = 0;
63 for (UINT32 i = 0; i < numChildren; i++)
64 {
65 HSceneObject child = mMainScene->mRoot->getChild(curIdx);
66
67 if (forceAll || !child->hasFlag(SOF_Persistent))
68 child->destroy();
69 else
70 curIdx++;
71 }
72
73 GameObjectManager::instance().destroyQueuedObjects();
74
75 HSceneObject newRoot = SceneObject::createInternal("SceneRoot");
76 _setRootNode(newRoot);
77 }
78
79 void SceneManager::loadScene(const HPrefab& scene)
80 {
81 HSceneObject root = scene->_instantiate(true);
82 _setRootNode(root);
83 }
84
85 HPrefab SceneManager::saveScene() const
86 {
87 HSceneObject sceneRoot = mMainScene->getRoot();
88 return Prefab::create(sceneRoot);
89 }
90
91 void SceneManager::_setRootNode(const HSceneObject& root)
92 {
93 if (root == nullptr)
94 return;
95
96 HSceneObject oldRoot = mMainScene->mRoot;
97
98 UINT32 numChildren = oldRoot->getNumChildren();
99 // Make sure to keep persistent objects
100
101 bs_frame_mark();
102 {
103 FrameVector<HSceneObject> toRemove;
104 for (UINT32 i = 0; i < numChildren; i++)
105 {
106 HSceneObject child = oldRoot->getChild(i);
107
108 if (child->hasFlag(SOF_Persistent))
109 toRemove.push_back(child);
110 }
111
112 for (auto& entry : toRemove)
113 entry->setParent(root, false);
114 }
115 bs_frame_clear();
116
117 mMainScene->mRoot = root;
118 mMainScene->mRoot->_setParent(HSceneObject());
119 mMainScene->mRoot->setScene(mMainScene);
120
121 oldRoot->destroy();
122 }
123
124 void SceneManager::_bindActor(const SPtr<SceneActor>& actor, const HSceneObject& so)
125 {
126 mBoundActors[actor.get()] = BoundActorData(actor, so);
127 actor->_updateState(*so, true);
128 }
129
130 void SceneManager::_unbindActor(const SPtr<SceneActor>& actor)
131 {
132 mBoundActors.erase(actor.get());
133 }
134
135 HSceneObject SceneManager::_getActorSO(const SPtr<SceneActor>& actor) const
136 {
137 auto iterFind = mBoundActors.find(actor.get());
138 if (iterFind != mBoundActors.end())
139 return iterFind->second.so;
140
141 return HSceneObject();
142 }
143
144 void SceneManager::_registerCamera(const SPtr<Camera>& camera)
145 {
146 mCameras[camera.get()] = camera;
147 }
148
149 void SceneManager::_unregisterCamera(const SPtr<Camera>& camera)
150 {
151 mCameras.erase(camera.get());
152
153 auto iterFind = std::find_if(mMainCameras.begin(), mMainCameras.end(),
154 [&](const SPtr<Camera>& x)
155 {
156 return x == camera;
157 });
158
159 if (iterFind != mMainCameras.end())
160 mMainCameras.erase(iterFind);
161 }
162
163 void SceneManager::_notifyMainCameraStateChanged(const SPtr<Camera>& camera)
164 {
165 auto iterFind = std::find_if(mMainCameras.begin(), mMainCameras.end(),
166 [&](const SPtr<Camera>& entry)
167 {
168 return entry == camera;
169 });
170
171 SPtr<Viewport> viewport = camera->getViewport();
172 if (camera->isMain())
173 {
174 if (iterFind == mMainCameras.end())
175 mMainCameras.push_back(mCameras[camera.get()]);
176
177 viewport->setTarget(mMainRT);
178 }
179 else
180 {
181 if (iterFind != mMainCameras.end())
182 mMainCameras.erase(iterFind);
183
184 if (viewport->getTarget() == mMainRT)
185 viewport->setTarget(nullptr);
186 }
187 }
188
189 void SceneManager::_updateCoreObjectTransforms()
190 {
191 for (auto& entry : mBoundActors)
192 entry.second.actor->_updateState(*entry.second.so);
193 }
194
195 SPtr<Camera> SceneManager::getMainCamera() const
196 {
197 if (mMainCameras.size() > 0)
198 return mMainCameras[0];
199
200 return nullptr;
201 }
202
203 void SceneManager::setMainRenderTarget(const SPtr<RenderTarget>& rt)
204 {
205 if (mMainRT == rt)
206 return;
207
208 mMainRTResizedConn.disconnect();
209
210 if (rt != nullptr)
211 mMainRTResizedConn = rt->onResized.connect(std::bind(&SceneManager::onMainRenderTargetResized, this));
212
213 mMainRT = rt;
214
215 float aspect = 1.0f;
216 if (rt != nullptr)
217 {
218 auto& rtProps = rt->getProperties();
219 aspect = rtProps.width / (float)rtProps.height;
220 }
221
222 for (auto& entry : mMainCameras)
223 {
224 entry->getViewport()->setTarget(rt);
225 entry->setAspectRatio(aspect);
226 }
227 }
228
229 void SceneManager::setComponentState(ComponentState state)
230 {
231 if(mDisableStateChange)
232 {
233 LOGWRN("Component state cannot be changed from the calling locating. Are you calling it from Component \
234 callbacks?");
235 return;
236 }
237
238 if (mComponentState == state)
239 return;
240
241 ComponentState oldState = mComponentState;
242
243 // Make sure to change the state before calling any callbacks, so callbacks can query the state
244 mComponentState = state;
245
246 // Make sure the per-state lists are up-to-date
247 processStateChanges();
248
249 ScopeToggle toggle(mDisableStateChange);
250
251 // Wake up all components with onInitialize/onEnable events if moving to running or paused state
252 if(state == ComponentState::Running || state == ComponentState::Paused)
253 {
254 if(oldState == ComponentState::Stopped)
255 {
256 // Disable, and then re-enable components that have an AlwaysRun flag
257 for(auto& entry : mActiveComponents)
258 {
259 if (entry->sceneObject()->getActive())
260 {
261 entry->onDisabled();
262 entry->onEnabled();
263 }
264 }
265
266 // Process any state changes queued by the component callbacks
267 processStateChanges();
268
269 // Trigger enable on all components that don't have AlwaysRun flag (at this point those will be all
270 // inactive components that have active scene object parents)
271 for(auto& entry : mInactiveComponents)
272 {
273 if (entry->sceneObject()->getActive())
274 {
275 entry->onEnabled();
276
277 if(state == ComponentState::Running)
278 mStateChanges.emplace_back(entry, ComponentStateEventType::Activated);
279 }
280 }
281
282 // Process any state changes queued by the component callbacks
283 processStateChanges();
284
285 // Initialize and enable uninitialized components
286 for(auto& entry : mUninitializedComponents)
287 {
288 entry->onInitialized();
289
290 if (entry->sceneObject()->getActive())
291 {
292 entry->onEnabled();
293 mStateChanges.emplace_back(entry, ComponentStateEventType::Activated);
294 }
295 else
296 mStateChanges.emplace_back(entry, ComponentStateEventType::Deactivated);
297 }
298
299 // Process any state changes queued by the component callbacks
300 processStateChanges();
301 }
302 }
303
304 // Stop updates on all active components
305 if(state == ComponentState::Paused || state == ComponentState::Stopped)
306 {
307 // Trigger onDisable events if stopping
308 if (state == ComponentState::Stopped)
309 {
310 for (const auto& component : mActiveComponents)
311 {
312 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
313
314 component->onDisabled();
315
316 if(alwaysRun)
317 component->onEnabled();
318 }
319 }
320
321 // Move from active to inactive list
322 for (INT32 i = 0; i < (INT32)mActiveComponents.size(); i++)
323 {
324 // Note: Purposely not a reference since the list changes in the add/remove methods below
325 const HComponent component = mActiveComponents[i];
326
327 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
328 if (alwaysRun)
329 continue;
330
331 removeFromStateList(component);
332 addToStateList(component, InactiveList);
333
334 i--; // Keep the same index next iteration to process the component we just swapped
335 }
336 }
337 }
338
339 void SceneManager::_notifyComponentCreated(const HComponent& component, bool parentActive)
340 {
341 // Note: This method must remain reentrant (in case the callbacks below trigger component state changes)
342
343 // Queue the change before any callbacks trigger, as the callbacks could trigger their own changes and they should
344 // be in order
345 mStateChanges.emplace_back(component, ComponentStateEventType::Created);
346 ScopeToggle toggle(mDisableStateChange);
347
348 component->onCreated();
349
350 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
351 if(alwaysRun || mComponentState != ComponentState::Stopped)
352 {
353 component->onInitialized();
354
355 if (parentActive)
356 component->onEnabled();
357 }
358 }
359
360 void SceneManager::_notifyComponentActivated(const HComponent& component, bool triggerEvent)
361 {
362 // Note: This method must remain reentrant (in case the callbacks below trigger component state changes)
363
364 // Queue the change before any callbacks trigger, as the callbacks could trigger their own changes and they should
365 // be in order
366 mStateChanges.emplace_back(component, ComponentStateEventType::Activated);
367 ScopeToggle toggle(mDisableStateChange);
368
369 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
370 if(alwaysRun || mComponentState != ComponentState::Stopped)
371 {
372 if (triggerEvent)
373 component->onEnabled();
374 }
375 }
376
377 void SceneManager::_notifyComponentDeactivated(const HComponent& component, bool triggerEvent)
378 {
379 // Note: This method must remain reentrant (in case the callbacks below trigger component state changes)
380
381 // Queue the change before any callbacks trigger, as the callbacks could trigger their own changes and they should
382 // be in order
383 mStateChanges.emplace_back(component, ComponentStateEventType::Deactivated);
384 ScopeToggle toggle(mDisableStateChange);
385
386 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
387 if(alwaysRun || mComponentState != ComponentState::Stopped)
388 {
389 if (triggerEvent)
390 component->onDisabled();
391 }
392 }
393
394 void SceneManager::_notifyComponentDestroyed(const HComponent& component, bool immediate)
395 {
396 // Note: This method must remain reentrant (in case the callbacks below trigger component state changes)
397
398 // Queue the change before any callbacks trigger, as the callbacks could trigger their own changes and they should
399 // be in order
400 if(!immediate)
401 {
402 // If destruction is immediate no point in queuing state change since it will be ignored anyway
403 mStateChanges.emplace_back(component, ComponentStateEventType::Destroyed);
404 }
405
406 ScopeToggle toggle(mDisableStateChange);
407
408 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
409 const bool isEnabled = component->sceneObject()->getActive() && (alwaysRun ||
410 mComponentState != ComponentState::Stopped);
411
412 if (isEnabled)
413 component->onDisabled();
414
415 component->onDestroyed();
416
417 if(immediate)
418 {
419 // Since the state change wasn't queued, remove the component from the list right away. Its expected the caller
420 // knows what is he doing.
421
422 UINT32 existingListType;
423 UINT32 existingIdx;
424 decodeComponentId(component->getSceneManagerId(), existingIdx, existingListType);
425
426 if(existingListType != 0)
427 removeFromStateList(component);
428 }
429 }
430
431 void SceneManager::addToStateList(const HComponent& component, UINT32 listType)
432 {
433 if(listType == 0)
434 return;
435
436 Vector<HComponent>& list = *mComponentsPerState[listType - 1];
437
438 const auto idx = (UINT32)list.size();
439 list.push_back(component);
440
441 component->setSceneManagerId(encodeComponentId(idx, listType));
442 }
443
444 void SceneManager::removeFromStateList(const HComponent& component)
445 {
446 UINT32 listType;
447 UINT32 idx;
448 decodeComponentId(component->getSceneManagerId(), idx, listType);
449
450 if(listType == 0)
451 return;
452
453 Vector<HComponent>& list = *mComponentsPerState[listType - 1];
454
455 UINT32 lastIdx;
456 decodeComponentId(list.back()->getSceneManagerId(), lastIdx, listType);
457
458 assert(list[idx] == component);
459
460 if (idx != lastIdx)
461 {
462 std::swap(list[idx], list[lastIdx]);
463 list[idx]->setSceneManagerId(encodeComponentId(idx, listType));
464 }
465
466 list.erase(list.end() - 1);
467 }
468
469 void SceneManager::processStateChanges()
470 {
471 const bool isStopped = mComponentState == ComponentState::Stopped;
472
473 for(auto& entry : mStateChanges)
474 {
475 const HComponent& component = entry.obj;
476 if(component.isDestroyed(false))
477 continue;
478
479 UINT32 existingListType;
480 UINT32 existingIdx;
481 decodeComponentId(component->getSceneManagerId(), existingIdx, existingListType);
482
483 const bool alwaysRun = component->hasFlag(ComponentFlag::AlwaysRun);
484 const bool isActive = component->SO()->getActive();
485
486 UINT32 listType = 0;
487 switch(entry.type)
488 {
489 case ComponentStateEventType::Created:
490 if (alwaysRun || !isStopped)
491 listType = isActive ? ActiveList : InactiveList;
492 else
493 listType = UninitializedList;
494 break;
495 case ComponentStateEventType::Activated:
496 case ComponentStateEventType::Deactivated:
497 if (alwaysRun || !isStopped)
498 listType = isActive ? ActiveList : InactiveList;
499 else
500 listType = (existingListType == UninitializedList) ? UninitializedList : InactiveList;
501 break;
502 case ComponentStateEventType::Destroyed:
503 listType = 0;
504 break;
505 default: break;
506 }
507
508 if(existingListType == listType)
509 continue;
510
511 if(existingListType != 0)
512 removeFromStateList(component);
513
514 addToStateList(component, listType);
515 }
516
517 mStateChanges.clear();
518 }
519
520
521 UINT32 SceneManager::encodeComponentId(UINT32 idx, UINT32 type)
522 {
523 assert(idx <= (0x3FFFFFFF));
524
525 return (type << 30) | idx;
526 }
527
528 void SceneManager::decodeComponentId(UINT32 id, UINT32& idx, UINT32& type)
529 {
530 idx = id & 0x3FFFFFFF;
531 type = id >> 30;
532 }
533
534 bool SceneManager::isComponentOfType(const HComponent& component, UINT32 rttiId)
535 {
536 return component->getRTTI()->getRTTIId() == rttiId;
537 }
538
539 void SceneManager::_update()
540 {
541 processStateChanges();
542
543 // Note: Eventually perform updates based on component types and/or on component priority. Right now we just
544 // iterate in an undefined order, but it wouldn't be hard to change it.
545
546 ScopeToggle toggle(mDisableStateChange);
547 for (auto& entry : mActiveComponents)
548 entry->update();
549
550 GameObjectManager::instance().destroyQueuedObjects();
551 }
552
553 void SceneManager::_fixedUpdate()
554 {
555 processStateChanges();
556
557 ScopeToggle toggle(mDisableStateChange);
558 for (auto& entry : mActiveComponents)
559 entry->fixedUpdate();
560 }
561
562 void SceneManager::registerNewSO(const HSceneObject& node)
563 {
564 if(mMainScene->getRoot())
565 node->setParent(mMainScene->getRoot());
566 }
567
568 void SceneManager::onMainRenderTargetResized()
569 {
570 auto& rtProps = mMainRT->getProperties();
571 float aspect = rtProps.width / (float)rtProps.height;
572
573 for (auto& entry : mMainCameras)
574 entry->setAspectRatio(aspect);
575 }
576
577 SceneManager& gSceneManager()
578 {
579 return SceneManager::instance();
580 }
581}
582