• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "internal_scene.h"
17 
18 #include <chrono>
19 #include <inttypes.h>
20 #include <mutex>
21 #include <scene/ext/intf_converting_value.h>
22 #include <scene/ext/intf_create_entity.h>
23 #include <scene/ext/util.h>
24 #include <scene/interface/intf_light.h>
25 #include <scene/interface/intf_mesh.h>
26 #include <scene/interface/intf_scene.h>
27 #include <scene/interface/intf_text.h>
28 
29 #include <3d/implementation_uids.h>
30 #include <render/intf_render_context.h>
31 #include <render/intf_renderer.h>
32 
33 #include <meta/api/engine/util.h>
34 #include <meta/interface/intf_startable.h>
35 
36 #include "component/generic_component.h"
37 #include "node/startable_handler.h"
38 #include "resource/ecs_animation.h"
39 #include "ecs_object.h"
40 
SCENE_BEGIN_NAMESPACE()41 SCENE_BEGIN_NAMESPACE()
42 
43 InternalScene::InternalScene(const IScene::Ptr& scene, IRenderContext::Ptr context, SceneOptions opts)
44     : scene_(scene), options_(BASE_NS::move(opts))
45 {
46     if (auto getter = interface_cast<IApplicationContextProvider>(context)) {
47         context_ = getter->GetApplicationContext();
48     }
49 
50     graphicsContext3D_ = CORE_NS::CreateInstance<CORE3D_NS::IGraphicsContext>(
51         *context->GetRenderer()->GetInterface<CORE_NS::IClassFactory>(), CORE3D_NS::UID_GRAPHICS_CONTEXT);
52     graphicsContext3D_->Init();
53 }
54 
~InternalScene()55 InternalScene::~InternalScene() {}
56 
Initialize()57 bool InternalScene::Initialize()
58 {
59     ecs_.reset(new Ecs);
60     if (!ecs_->Initialize(self_.lock(), options_)) {
61         CORE_LOG_E("failed to initialize ecs");
62         return false;
63     }
64     return true;
65 }
66 
GetOptions() const67 SceneOptions InternalScene::GetOptions() const
68 {
69     return options_;
70 }
71 
Uninitialize()72 void InternalScene::Uninitialize()
73 {
74     CORE_LOG_D("InternalScene::Uninitialize");
75     {
76         std::unique_lock lock { mutex_ };
77         syncs_.clear();
78     }
79     nodes_.clear();
80     animations_.clear();
81     componentFactories_.clear();
82     renderingCameras_.clear();
83 
84     if (ecs_) {
85         ecs_->Uninitialize();
86     }
87 
88     if (const auto rctx = GetRenderContextPtr()) {
89         // Do a "empty render" to flush out the gpu resources instantly.
90         rctx->GetRenderer().RenderFrame({});
91     }
92 }
93 
CreateDefaultEntity(CORE_NS::IEcs & ecs)94 static CORE_NS::Entity CreateDefaultEntity(CORE_NS::IEcs& ecs)
95 {
96     CORE_NS::IEntityManager& em = ecs.GetEntityManager();
97     return em.Create();
98 }
99 
CreateNode(BASE_NS::string_view path,META_NS::ObjectId id)100 INode::Ptr InternalScene::CreateNode(BASE_NS::string_view path, META_NS::ObjectId id)
101 {
102     auto& r = META_NS::GetObjectRegistry();
103 
104     if (ecs_->FindNode(path)) {
105         CORE_LOG_E("Node exists already [path=%s]", BASE_NS::string(path).c_str());
106         return nullptr;
107     }
108 
109     auto parent = ecs_->FindNodeParent(path);
110     if (!parent) {
111         CORE_LOG_E("No parent for node [path=%s]", BASE_NS::string(path).c_str());
112         return nullptr;
113     }
114 
115     if (!id.IsValid()) {
116         id = ClassId::Node;
117     }
118 
119     auto node = r.Create<INode>(id);
120     if (!node) {
121         CORE_LOG_E(
122             "Failed to create node object [path=%s, id=%s]", BASE_NS::string(path).c_str(), id.ToString().c_str());
123         return nullptr;
124     }
125     CORE_NS::Entity ent;
126     if (auto ce = interface_pointer_cast<ICreateEntity>(node)) {
127         ent = ce->CreateEntity(self_.lock());
128     } else {
129         ent = CreateDefaultEntity(*ecs_->ecs);
130     }
131     if (!CORE_NS::EntityUtil::IsValid(ent)) {
132         CORE_LOG_E("Failed to create entity [path=%s, id=%s]", BASE_NS::string(path).c_str(), id.ToString().c_str());
133         return nullptr;
134     }
135     ecs_->AddDefaultComponents(ent);
136     ecs_->SetNodeName(ent, EntityName(path)); // remove when reworking names for scene objects
137     if (!ConstructNodeImpl(ent, node)) {
138         ecs_->RemoveEntity(ent);
139         return nullptr;
140         ;
141     }
142     ecs_->SetNodeParentAndName(ent, EntityName(path), parent);
143     return node;
144 }
145 
CreateObject(META_NS::ObjectId id)146 META_NS::IObject::Ptr InternalScene::CreateObject(META_NS::ObjectId id)
147 {
148     auto& r = META_NS::GetObjectRegistry();
149     auto md = CreateRenderContextArg(GetContext());
150     if (md) {
151         md->AddProperty(META_NS::ConstructProperty<IInternalScene::Ptr>("Scene", self_.lock()));
152     }
153     auto object = r.Create<META_NS::IObject>(id, md);
154     if (!object) {
155         CORE_LOG_E("Failed to create scene object [id=%s]", id.ToString().c_str());
156         return nullptr;
157     }
158     if (auto acc = interface_cast<IEcsObjectAccess>(object)) {
159         CORE_NS::Entity ent;
160         if (auto ce = interface_pointer_cast<ICreateEntity>(object)) {
161             ent = ce->CreateEntity(self_.lock());
162         } else {
163             ent = CreateDefaultEntity(*ecs_->ecs);
164         }
165         if (!CORE_NS::EntityUtil::IsValid(ent)) {
166             CORE_LOG_E("Failed to create entity [id=%s]", id.ToString().c_str());
167             return nullptr;
168         }
169         auto eobj = ecs_->GetEcsObject(ent);
170         if (!acc->SetEcsObject(eobj)) {
171             return nullptr;
172         }
173     }
174     return object;
175 }
176 
ConstructNodeImpl(CORE_NS::Entity ent,INode::Ptr node) const177 INode::Ptr InternalScene::ConstructNodeImpl(CORE_NS::Entity ent, INode::Ptr node) const
178 {
179     auto acc = interface_cast<IEcsObjectAccess>(node);
180     if (!acc) {
181         return nullptr;
182     }
183     auto& r = META_NS::GetObjectRegistry();
184 
185     auto eobj = ecs_->GetEcsObject(ent);
186     if (!eobj) {
187         return nullptr;
188     }
189     AttachComponents(node, eobj, ent);
190 
191     if (!acc->SetEcsObject(eobj)) {
192         return nullptr;
193     }
194 
195     nodes_[ent] = node;
196     return node;
197 }
198 
DeducePrimaryNodeType(CORE_NS::Entity ent) const199 META_NS::ObjectId InternalScene::DeducePrimaryNodeType(CORE_NS::Entity ent) const
200 {
201     if (ecs_->cameraComponentManager->HasComponent(ent)) {
202         return ClassId::CameraNode;
203     }
204     if (ecs_->lightComponentManager->HasComponent(ent)) {
205         return ClassId::LightNode;
206     }
207     if (ecs_->textComponentManager && ecs_->textComponentManager->HasComponent(ent)) {
208         return ClassId::TextNode;
209     }
210     if (ecs_->renderMeshComponentManager->HasComponent(ent)) {
211         return ClassId::MeshNode;
212     }
213     return ClassId::Node;
214 }
215 
ConstructNode(CORE_NS::Entity ent,META_NS::ObjectId id) const216 INode::Ptr InternalScene::ConstructNode(CORE_NS::Entity ent, META_NS::ObjectId id) const
217 {
218     auto& r = META_NS::GetObjectRegistry();
219     if (!id.IsValid()) {
220         id = DeducePrimaryNodeType(ent);
221     }
222 
223     auto node = r.Create<INode>(id);
224     if (!node) {
225         CORE_LOG_E("Failed to create node object [id=%s]", id.ToString().c_str());
226         return nullptr;
227     }
228 
229     return ConstructNodeImpl(ent, node);
230 }
231 
CreateEcsComponent(const INode::Ptr & node,BASE_NS::string_view componentName)232 IComponent::Ptr InternalScene::CreateEcsComponent(const INode::Ptr& node, BASE_NS::string_view componentName)
233 {
234     // First check we already have the component
235     auto attach = interface_cast<META_NS::IAttach>(node);
236     if (!attach) {
237         return {};
238     }
239     if (auto cont = attach->GetAttachmentContainer(true)) {
240         if (auto existing = cont->FindAny<IComponent>(componentName, META_NS::TraversalType::NO_HIERARCHY)) {
241             return existing;
242         }
243     }
244     // Then find a component manager with a matching name
245     IEcsObject::Ptr ecso;
246     if (auto acc = interface_cast<IEcsObjectAccess>(node)) {
247         ecso = acc->GetEcsObject();
248     }
249     if (ecs_ && ecso) {
250         if (auto ecs = ecs_->GetNativeEcs()) {
251             for (auto&& manager : ecs->GetComponentManagers()) {
252                 if (manager->GetName() == componentName) {
253                     // Also create the Ecs component if not there already
254                     if (auto component = CreateComponent(manager, ecso, true)) {
255                         // We don't call component->PopulateAllProperties() here, i.e. if the component was newly
256                         // created its properties will not be populated
257                         attach->Attach(component);
258                         return component;
259                     }
260                 }
261             }
262         }
263     }
264     return {};
265 }
266 
CreateComponent(CORE_NS::IComponentManager * m,const IEcsObject::Ptr & ecsObject,bool createEcsComponent) const267 IComponent::Ptr InternalScene::CreateComponent(
268     CORE_NS::IComponentManager* m, const IEcsObject::Ptr& ecsObject, bool createEcsComponent) const
269 {
270     if (!m) {
271         return {};
272     }
273     auto& r = META_NS::GetObjectRegistry();
274     IComponent::Ptr comp;
275     ;
276     if (createEcsComponent) {
277         if (auto entity = ecsObject->GetEntity(); CORE_NS::EntityUtil::IsValid(entity)) {
278             if (!m->HasComponent(entity)) {
279                 m->Create(entity);
280             }
281         }
282     }
283     if (auto fac = FindComponentFactory(m->GetUid())) {
284         comp = fac->CreateComponent(ecsObject);
285     } else {
286         auto md = r.Create<META_NS::IMetadata>(META_NS::ClassId::Object);
287         md->AddProperty(META_NS::ConstructProperty<BASE_NS::string>("Component", BASE_NS::string(m->GetName())));
288         comp = r.Create<IComponent>(ClassId::GenericComponent, md);
289         if (auto acc = interface_cast<IEcsObjectAccess>(comp)) {
290             if (!acc->SetEcsObject(ecsObject)) {
291                 return nullptr;
292             }
293         }
294     }
295     return comp;
296 }
297 
AttachComponents(const INode::Ptr & node,const IEcsObject::Ptr & ecsObject,CORE_NS::Entity ent) const298 void InternalScene::AttachComponents(
299     const INode::Ptr& node, const IEcsObject::Ptr& ecsObject, CORE_NS::Entity ent) const
300 {
301     auto& r = META_NS::GetObjectRegistry();
302     auto att = interface_cast<META_NS::IAttach>(node);
303     if (!att) {
304         return;
305     }
306 
307     auto attachments = att->GetAttachmentContainer(true);
308 
309     BASE_NS::vector<CORE_NS::IComponentManager*> managers;
310     ecs_->ecs->GetComponents(ent, managers);
311     for (auto m : managers) {
312         if (!attachments->FindByName(m->GetName())) {
313             if (auto comp = CreateComponent(m, ecsObject, false)) {
314                 att->Attach(comp);
315             } else {
316                 CORE_LOG_E("Failed to construct component for '%s'", BASE_NS::string(m->GetName()).c_str());
317             }
318         }
319     }
320 }
321 
FindNode(CORE_NS::Entity ent,META_NS::ObjectId id) const322 INode::Ptr InternalScene::FindNode(CORE_NS::Entity ent, META_NS::ObjectId id) const
323 {
324     if (ecs_->IsNodeEntity(ent)) {
325         auto it = nodes_.find(ent);
326         if (it != nodes_.end()) {
327             return it->second;
328         }
329         return ConstructNode(ent, id);
330     }
331 
332     CORE_LOG_W("Could not find entity: %" PRIu64, ent.id);
333     return nullptr;
334 }
335 
FindNode(BASE_NS::string_view path,META_NS::ObjectId id) const336 INode::Ptr InternalScene::FindNode(BASE_NS::string_view path, META_NS::ObjectId id) const
337 {
338     auto npath = NormalisePath(path);
339     auto n = ecs_->FindNode(npath);
340     if (n) {
341         auto it = nodes_.find(n->GetEntity());
342         if (it != nodes_.end()) {
343             return it->second;
344         }
345         return ConstructNode(n->GetEntity(), id);
346     }
347 
348     CORE_LOG_W("Could not find node: %s", BASE_NS::string(npath).c_str());
349     return nullptr;
350 }
351 
ReleaseCached(NodesType::iterator it)352 INode::Ptr InternalScene::ReleaseCached(NodesType::iterator it)
353 {
354     auto node = BASE_NS::move(it->second);
355     nodes_.erase(it);
356     if (auto i = interface_cast<INodeNotify>(node)) {
357         if (i->IsListening()) {
358             ListenNodeChanges(false);
359         }
360     }
361     return node;
362 }
363 
ReleaseChildNodes(const IEcsObject::Ptr & eobj)364 void InternalScene::ReleaseChildNodes(const IEcsObject::Ptr& eobj)
365 {
366     if (auto n = ecs_->GetNode(eobj->GetEntity())) {
367         for (auto&& c : n->GetChildren()) {
368             auto it = nodes_.find(c->GetEntity());
369             if (it != nodes_.end()) {
370                 auto nn = it->second;
371                 ReleaseNode(BASE_NS::move(nn), true);
372             }
373         }
374     }
375 }
376 
ReleaseNode(INode::Ptr && node,bool recursive)377 bool InternalScene::ReleaseNode(INode::Ptr&& node, bool recursive)
378 {
379     if (node) {
380         IEcsObject::Ptr eobj;
381         if (auto acc = interface_cast<IEcsObjectAccess>(node)) {
382             eobj = acc->GetEcsObject();
383         }
384         node.reset();
385         if (eobj) {
386             auto it = nodes_.find(eobj->GetEntity());
387             if (it != nodes_.end()) {
388                 // are we the only owner?
389                 if (it->second.use_count() == 1) {
390                     node = ReleaseCached(it);
391                 }
392             }
393             if (recursive) {
394                 ReleaseChildNodes(eobj);
395             }
396             if (node) {
397                 ecs_->RemoveEcsObject(eobj);
398                 return true;
399             }
400         }
401     }
402     return false;
403 }
404 
RemoveNode(const INode::Ptr & node)405 bool InternalScene::RemoveNode(const INode::Ptr& node)
406 {
407     if (node) {
408         if (auto acc = interface_cast<IEcsObjectAccess>(node)) {
409             if (auto eobj = acc->GetEcsObject()) {
410                 auto decents = ecs_->GetNodeDescendants(eobj->GetEntity());
411                 for (auto&& ent : decents) {
412                     if (auto it = nodes_.find(ent); it != nodes_.end()) {
413                         ReleaseCached(it);
414                     }
415                     ecs_->RemoveEntity(ent);
416                 }
417                 return true;
418             }
419         }
420     }
421     return false;
422 }
423 
424 /// Returns a list of instantiated child nodes of root (including root) which implement INodeNotify
GetNotifiableNodesFromHierarchy(CORE_NS::Entity root)425 BASE_NS::vector<INodeNotify::Ptr> InternalScene::GetNotifiableNodesFromHierarchy(CORE_NS::Entity root)
426 {
427     BASE_NS::vector<INodeNotify::Ptr> notify;
428     auto findNode = [this](CORE_NS::Entity entity) {
429         auto n = nodes_.find(entity);
430         return n != nodes_.end() ? interface_pointer_cast<INodeNotify>(n->second) : nullptr;
431     };
432     // Add root to the list
433     if (auto n = findNode(root)) {
434         notify.emplace_back(BASE_NS::move(n));
435     }
436     // Add descendants to the list
437     auto descendants = ecs_->GetNodeDescendants(root);
438     notify.reserve(descendants.size() + 1);
439     for (auto&& d : descendants) {
440         if (auto n = findNode(d)) {
441             notify.emplace_back(BASE_NS::move(n));
442         }
443     }
444     return notify;
445 }
446 
SetEntityActive(const BASE_NS::shared_ptr<IEcsObject> & child,bool active)447 void InternalScene::SetEntityActive(const BASE_NS::shared_ptr<IEcsObject>& child, bool active)
448 {
449     if (!child || !ecs_) {
450         return;
451     }
452     const auto entity = child->GetEntity();
453     if (!active) {
454         for (auto&& node : GetNotifiableNodesFromHierarchy(entity)) {
455             node->OnNodeActiveStateChanged(INodeNotify::NodeActiteStateInfo::DEACTIVATING);
456         }
457     }
458     ecs_->SetNodesActive(entity, active);
459     if (active) {
460         for (auto&& node : GetNotifiableNodesFromHierarchy(entity)) {
461             node->OnNodeActiveStateChanged(INodeNotify::NodeActiteStateInfo::ACTIVATED);
462         }
463     }
464 }
465 
GetChildren(const IEcsObject::Ptr & obj) const466 BASE_NS::vector<INode::Ptr> InternalScene::GetChildren(const IEcsObject::Ptr& obj) const
467 {
468     BASE_NS::vector<INode::Ptr> res;
469     if (auto node = ecs_->GetNode(obj->GetEntity())) {
470         for (auto&& c : node->GetChildren()) {
471             if (auto n = FindNode(c->GetEntity(), {})) {
472                 res.push_back(n);
473             }
474         }
475     }
476     return res;
477 }
RemoveChild(const BASE_NS::shared_ptr<IEcsObject> & object,const BASE_NS::shared_ptr<IEcsObject> & child)478 bool InternalScene::RemoveChild(
479     const BASE_NS::shared_ptr<IEcsObject>& object, const BASE_NS::shared_ptr<IEcsObject>& child)
480 {
481     bool ret = false;
482     if (auto node = ecs_->GetNode(object->GetEntity())) {
483         if (auto childNode = ecs_->GetNode(child->GetEntity())) {
484             ret = node->RemoveChild(*childNode);
485             if (ret) {
486                 SetEntityActive(child, false);
487             }
488         }
489     }
490     return ret;
491 }
AddChild(const BASE_NS::shared_ptr<IEcsObject> & object,const INode::Ptr & child,size_t index)492 bool InternalScene::AddChild(const BASE_NS::shared_ptr<IEcsObject>& object, const INode::Ptr& child, size_t index)
493 {
494     bool ret = false;
495     if (ecs_->IsNodeEntity(object->GetEntity())) {
496         if (auto acc = interface_cast<IEcsObjectAccess>(child)) {
497             auto ecsobj = acc->GetEcsObject();
498             SetEntityActive(ecsobj, true);
499             if (auto node = ecs_->GetNode(object->GetEntity())) {
500                 if (auto childNode = ecs_->GetNode(ecsobj->GetEntity())) {
501                     if (node->InsertChild(index, *childNode)) {
502                         nodes_[ecsobj->GetEntity()] = child;
503                         ret = true;
504                     }
505                 }
506             }
507         }
508     }
509     return ret;
510 }
511 
GetScene() const512 BASE_NS::shared_ptr<IScene> InternalScene::GetScene() const
513 {
514     return scene_.lock();
515 }
516 
SchedulePropertyUpdate(const IEcsObject::Ptr & obj)517 void InternalScene::SchedulePropertyUpdate(const IEcsObject::Ptr& obj)
518 {
519     std::unique_lock lock { mutex_ };
520     syncs_[obj.get()] = obj;
521 }
522 
SyncProperties()523 void InternalScene::SyncProperties()
524 {
525     UpdateSyncProperties(false);
526 }
527 
UpdateSyncProperties(bool resetPending)528 bool InternalScene::UpdateSyncProperties(bool resetPending)
529 {
530     bool pending = false;
531     BASE_NS::unordered_map<void*, IEcsObject::WeakPtr> syncs;
532     {
533         std::unique_lock lock { mutex_ };
534         syncs = BASE_NS::move(syncs_);
535         pending = pendingRender_;
536         if (resetPending) {
537             pendingRender_ = false;
538         }
539     }
540 
541     for (auto&& v : syncs) {
542         if (auto o = v.second.lock()) {
543             o->SyncProperties();
544         }
545     }
546     return pending;
547 }
548 
Update(const UpdateInfo & info)549 void InternalScene::Update(const UpdateInfo& info)
550 {
551     using namespace std::chrono;
552     bool pending;
553     if (info.syncProperties) {
554         pending = UpdateSyncProperties(true);
555     } else {
556         std::unique_lock lock { mutex_ };
557         pending = pendingRender_;
558         pendingRender_ = false;
559     }
560 
561     ecs_->ecs->ProcessEvents();
562 
563     uint64_t currentTime {};
564 
565     if (info.clock) {
566         currentTime = info.clock->GetTime().ToMicroseconds();
567     } else {
568         currentTime =
569             static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
570     }
571 
572     if (firstTime_ == ~0u) {
573         previousFrameTime_ = firstTime_ = currentTime;
574     }
575     auto deltaTime = currentTime - previousFrameTime_;
576     constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
577     if (deltaTime > limitHz) {
578         deltaTime = limitHz; // clamp the time step to no longer than 15hz.
579     }
580     previousFrameTime_ = currentTime;
581     const uint64_t totalTime = currentTime - firstTime_;
582 
583     bool needsRender = ecs_->ecs->Update(totalTime, deltaTime);
584 
585     ecs_->ecs->ProcessEvents();
586 
587     if ((needsRender && mode_ != RenderMode::MANUAL) || pending) {
588         auto renderHandles = graphicsContext3D_->GetRenderNodeGraphs(*ecs_->ecs);
589         if (!renderHandles.empty()) {
590             // The scene needs to be rendered.
591             if (auto rctx = GetRenderContextPtr()) {
592                 RENDER_NS::IRenderer& renderer = rctx->GetRenderer();
593                 renderer.RenderDeferred(renderHandles);
594                 NotifyRenderingCameras();
595             }
596         }
597     }
598 }
599 
Update(bool syncProperties)600 void InternalScene::Update(bool syncProperties)
601 {
602     IInternalSceneCore::UpdateInfo info;
603     info.syncProperties = syncProperties;
604     Update(info);
605 }
606 
NotifyRenderingCameras()607 void InternalScene::NotifyRenderingCameras()
608 {
609     for (auto it = renderingCameras_.begin(); it != renderingCameras_.end();) {
610         if (auto c = it->lock()) {
611             c->NotifyRenderTargetChanged();
612             ++it;
613         } else {
614             it = renderingCameras_.erase(it);
615         }
616     }
617 }
618 
GetCameras() const619 BASE_NS::vector<ICamera::Ptr> InternalScene::GetCameras() const
620 {
621     BASE_NS::vector<ICamera::Ptr> ret;
622 
623     for (size_t i = 0; i != ecs_->cameraComponentManager->GetComponentCount(); ++i) {
624         if (auto n = interface_pointer_cast<ICamera>(
625                 FindNode(ecs_->cameraComponentManager->GetEntity(i), ClassId::CameraNode))) {
626             ret.push_back(n);
627         }
628     }
629 
630     return ret;
631 }
632 
GetAnimations() const633 BASE_NS::vector<META_NS::IAnimation::Ptr> InternalScene::GetAnimations() const
634 {
635     BASE_NS::vector<META_NS::IAnimation::Ptr> ret;
636 
637     for (size_t i = 0; i != ecs_->animationComponentManager->GetComponentCount(); ++i) {
638         auto ent = ecs_->animationComponentManager->GetEntity(i);
639         META_NS::IAnimation::Ptr anim;
640         if (auto it = animations_.find(ent); it != animations_.end()) {
641             anim = it->second.lock();
642         }
643         if (!anim) {
644             anim = META_NS::GetObjectRegistry().Create<META_NS::IAnimation>(ClassId::EcsAnimation);
645             if (auto acc = interface_cast<IEcsObjectAccess>(anim)) {
646                 acc->SetEcsObject(ecs_->GetEcsObject(ent));
647                 animations_[ent] = anim;
648             }
649         }
650         if (anim) {
651             ret.push_back(anim);
652         } else {
653             CORE_LOG_W("Failed to create EcsAnimation object");
654         }
655     }
656 
657     return ret;
658 }
659 
RegisterComponent(const BASE_NS::Uid & id,const IComponentFactory::Ptr & p)660 void InternalScene::RegisterComponent(const BASE_NS::Uid& id, const IComponentFactory::Ptr& p)
661 {
662     componentFactories_[id] = p;
663 }
664 
UnregisterComponent(const BASE_NS::Uid & id)665 void InternalScene::UnregisterComponent(const BASE_NS::Uid& id)
666 {
667     componentFactories_.erase(id);
668 }
669 
FindComponentFactory(const BASE_NS::Uid & id) const670 BASE_NS::shared_ptr<IComponentFactory> InternalScene::FindComponentFactory(const BASE_NS::Uid& id) const
671 {
672     auto it = componentFactories_.find(id);
673     return it != componentFactories_.end() ? it->second : nullptr;
674 }
675 
SyncProperty(const META_NS::IProperty::ConstPtr & p,META_NS::EngineSyncDirection dir)676 bool InternalScene::SyncProperty(const META_NS::IProperty::ConstPtr& p, META_NS::EngineSyncDirection dir)
677 {
678     META_NS::IEngineValue::Ptr value = GetEngineValueFromProperty(p);
679     if (!value) {
680         if (auto i = META_NS::GetFirstValueFromProperty<IConvertingValue>(p)) {
681             value = GetEngineValueFromProperty(i->GetTargetProperty());
682         }
683     }
684     META_NS::InterfaceUniqueLock valueLock { value };
685     return value && value->Sync(dir);
686 }
687 
AddRenderingCamera(const IInternalCamera::Ptr & camera)688 void InternalScene::AddRenderingCamera(const IInternalCamera::Ptr& camera)
689 {
690     for (auto&& v : renderingCameras_) {
691         if (camera == v.lock()) {
692             return;
693         }
694     }
695     renderingCameras_.push_back(camera);
696 }
RemoveRenderingCamera(const IInternalCamera::Ptr & camera)697 void InternalScene::RemoveRenderingCamera(const IInternalCamera::Ptr& camera)
698 {
699     for (auto it = renderingCameras_.begin(); it != renderingCameras_.end(); ++it) {
700         if (camera == it->lock()) {
701             renderingCameras_.erase(it);
702             return;
703         }
704     }
705 }
706 
SetRenderMode(RenderMode mode)707 bool InternalScene::SetRenderMode(RenderMode mode)
708 {
709     mode_ = mode;
710     ecs_->ecs->SetRenderMode(
711         mode == RenderMode::IF_DIRTY ? CORE_NS::IEcs::RENDER_IF_DIRTY : CORE_NS::IEcs::RENDER_ALWAYS);
712     return true;
713 }
GetRenderMode() const714 RenderMode InternalScene::GetRenderMode() const
715 {
716     return mode_;
717 }
RenderFrame()718 void InternalScene::RenderFrame()
719 {
720     std::unique_lock lock { mutex_ };
721     pendingRender_ = true;
722 }
HasPendingRender() const723 bool InternalScene::HasPendingRender() const
724 {
725     std::unique_lock lock { mutex_ };
726     return pendingRender_;
727 }
728 
MapHitResults(const BASE_NS::vector<CORE3D_NS::RayCastResult> & res,const RayCastOptions & options) const729 NodeHits InternalScene::MapHitResults(
730     const BASE_NS::vector<CORE3D_NS::RayCastResult>& res, const RayCastOptions& options) const
731 {
732     NodeHits result;
733     CORE3D_NS::ISceneNode* n = nullptr;
734     if (auto obj = interface_cast<IEcsObjectAccess>(options.node)) {
735         if (auto ecs = obj->GetEcsObject()) {
736             n = ecs_->GetNode(ecs->GetEntity());
737         }
738     }
739 
740     for (auto&& v : res) {
741         NodeHit h;
742         if (v.node && (!n || n->IsAncestorOf(*v.node))) {
743             h.node = FindNode(v.node->GetEntity(), {});
744             h.distance = v.distance;
745             h.distanceToCenter = v.centerDistance;
746             h.position = v.worldPosition;
747             result.push_back(BASE_NS::move(h));
748         }
749     }
750     return result;
751 }
752 
CastRay(const BASE_NS::Math::Vec3 & pos,const BASE_NS::Math::Vec3 & dir,const RayCastOptions & options) const753 NodeHits InternalScene::CastRay(
754     const BASE_NS::Math::Vec3& pos, const BASE_NS::Math::Vec3& dir, const RayCastOptions& options) const
755 {
756     NodeHits result;
757     if (ecs_->picking) {
758         result = MapHitResults(ecs_->picking->RayCast(*ecs_->ecs, pos, dir, options.layerMask), options);
759     }
760     return result;
761 }
CastRay(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec2 & pos,const RayCastOptions & options) const762 NodeHits InternalScene::CastRay(
763     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec2& pos, const RayCastOptions& options) const
764 {
765     NodeHits result;
766     if (ecs_->picking) {
767         result = MapHitResults(
768             ecs_->picking->RayCastFromCamera(*ecs_->ecs, entity->GetEntity(), pos, options.layerMask), options);
769     }
770     return result;
771 }
ScreenPositionToWorld(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec3 & pos) const772 BASE_NS::Math::Vec3 InternalScene::ScreenPositionToWorld(
773     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec3& pos) const
774 {
775     BASE_NS::Math::Vec3 result;
776     if (ecs_->picking) {
777         result = ecs_->picking->ScreenToWorld(*ecs_->ecs, entity->GetEntity(), pos);
778     }
779     return result;
780 }
WorldPositionToScreen(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec3 & pos) const781 BASE_NS::Math::Vec3 InternalScene::WorldPositionToScreen(
782     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec3& pos) const
783 {
784     BASE_NS::Math::Vec3 result;
785     if (ecs_->picking) {
786         result = ecs_->picking->WorldToScreen(*ecs_->ecs, entity->GetEntity(), pos);
787     }
788     return result;
789 }
790 
ListenNodeChanges(bool enabled)791 void InternalScene::ListenNodeChanges(bool enabled)
792 {
793     bool change = false;
794     if (enabled) {
795         change = !nodeListening_++;
796     } else if (nodeListening_ > 0) {
797         change = !--nodeListening_;
798     }
799     if (change) {
800         ecs_->ListenNodeChanges(enabled);
801     }
802 }
803 
OnChildChanged(META_NS::ContainerChangeType type,CORE_NS::Entity parent,CORE_NS::Entity childEntity,size_t index)804 void InternalScene::OnChildChanged(
805     META_NS::ContainerChangeType type, CORE_NS::Entity parent, CORE_NS::Entity childEntity, size_t index)
806 {
807     if (auto it = nodes_.find(parent); it != nodes_.end()) {
808         if (auto i = interface_cast<INodeNotify>(it->second)) {
809             if (auto child = FindNode(childEntity, {})) {
810                 i->OnChildChanged(type, child, index);
811             } else {
812                 CORE_LOG_W("child changed but cannot construct it?!");
813             }
814         }
815     }
816 }
817 
GetNodes() const818 BASE_NS::vector<INode::Ptr> InternalScene::GetNodes() const
819 {
820     // This could be improved to traverse the Node system, and get a list of nodes that we have a wrapper for in a given
821     // traversal order
822     BASE_NS::vector<INode::Ptr> nodes;
823     nodes.reserve(nodes_.size());
824     for (auto&& n : nodes_) {
825         nodes.push_back(n.second);
826     }
827     return nodes;
828 }
829 
StartAllStartables(META_NS::IStartableController::ControlBehavior behavior)830 void InternalScene::StartAllStartables(META_NS::IStartableController::ControlBehavior behavior)
831 {
832     if (options_.enableStartables) {
833         if (auto me = self_.lock()) {
834             for (auto&& n : GetNodes()) {
835                 Internal::StartAllStartables(
836                     me, StartableHandler::StartType::DEFERRED, interface_pointer_cast<META_NS::IObject>(n));
837             }
838         }
839     }
840 }
841 
StopAllStartables(META_NS::IStartableController::ControlBehavior behavior)842 void InternalScene::StopAllStartables(META_NS::IStartableController::ControlBehavior behavior)
843 {
844     if (options_.enableStartables) {
845         for (auto&& n : GetNodes()) {
846             Internal::StopAllStartables(interface_pointer_cast<META_NS::IObject>(n));
847         }
848     }
849 }
850 
851 SCENE_END_NAMESPACE()
852