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 | |
17 | namespace 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 | |