• 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 <cinttypes>
19 #include <scene/ext/intf_converting_value.h>
20 #include <scene/ext/intf_create_entity.h>
21 #include <scene/ext/util.h>
22 #include <scene/interface/intf_light.h>
23 #include <scene/interface/intf_mesh.h>
24 #include <scene/interface/intf_scene.h>
25 #include <scene/interface/intf_text.h>
26 
27 #include <3d/implementation_uids.h>
28 #include <render/intf_render_context.h>
29 #include <render/intf_renderer.h>
30 
31 #include <meta/api/engine/util.h>
32 
33 #include "../component/generic_component.h"
34 #include "../ecs_animation.h"
35 #include "ecs_object.h"
36 
37 #include <3d/util/intf_render_util.h>
38 
SCENE_BEGIN_NAMESPACE()39 SCENE_BEGIN_NAMESPACE()
40 
41 InternalScene::InternalScene(const IScene::Ptr& scene, META_NS::ITaskQueue::Ptr engine, META_NS::ITaskQueue::Ptr app,
42     BASE_NS::shared_ptr<RENDER_NS::IRenderContext> context)
43     : scene_(scene), engineQueue_(BASE_NS::move(engine)), appQueue_(BASE_NS::move(app)),
44       renderContext_(BASE_NS::move(context))
45 {
46     graphicsContext3D_ = CORE_NS::CreateInstance<CORE3D_NS::IGraphicsContext>(
47         *renderContext_->GetInterface<CORE_NS::IClassFactory>(), CORE3D_NS::UID_GRAPHICS_CONTEXT);
48     graphicsContext3D_->Init();
49 }
50 
~InternalScene()51 InternalScene::~InternalScene() {}
52 
Initialize()53 bool InternalScene::Initialize()
54 {
55     ecs_.reset(new Ecs);
56     if (!ecs_->Initialize(self_.lock())) {
57         CORE_LOG_E("failed to initialize ecs");
58         return false;
59     }
60     return true;
61 }
62 
Uninitialize()63 void InternalScene::Uninitialize()
64 {
65     CORE_LOG_D("InternalScene::Uninitialize");
66     {
67         std::unique_lock lock { mutex_ };
68         syncs_.clear();
69     }
70     nodes_.clear();
71 
72     ecs_->Uninitialize();
73     if (graphicsContext3D_) {
74         graphicsContext3D_->GetRenderContext().GetRenderer().RenderFrame({});
75     }
76 }
77 
GetEngineTaskQueue() const78 META_NS::ITaskQueue::Ptr InternalScene::GetEngineTaskQueue() const
79 {
80     return engineQueue_;
81 }
GetAppTaskQueue() const82 META_NS::ITaskQueue::Ptr InternalScene::GetAppTaskQueue() const
83 {
84     return appQueue_;
85 }
86 
CreateDefaultEntity(CORE_NS::IEcs & ecs)87 static CORE_NS::Entity CreateDefaultEntity(CORE_NS::IEcs& ecs)
88 {
89     CORE_NS::IEntityManager& em = ecs.GetEntityManager();
90     return em.Create();
91 }
92 
CreateNode(BASE_NS::string_view path,META_NS::ObjectId id)93 INode::Ptr InternalScene::CreateNode(BASE_NS::string_view path, META_NS::ObjectId id)
94 {
95     auto& r = META_NS::GetObjectRegistry();
96 
97     if (ecs_->FindNode(path)) {
98         CORE_LOG_E("Node exists already [path=%s]", BASE_NS::string(path).c_str());
99         return nullptr;
100     }
101 
102     auto parent = ecs_->FindNodeParent(path);
103     if (!parent) {
104         CORE_LOG_E("No parent for node [path=%s]", BASE_NS::string(path).c_str());
105         return nullptr;
106     }
107 
108     if (!id.IsValid()) {
109         id = ClassId::Node;
110     }
111 
112     auto node = r.Create<INode>(id);
113     if (!node) {
114         CORE_LOG_E(
115             "Failed to create node object [path=%s, id=%s]", BASE_NS::string(path).c_str(), id.ToString().c_str());
116         return nullptr;
117     }
118     CORE_NS::Entity ent;
119     if (auto ce = interface_pointer_cast<ICreateEntity>(node)) {
120         ent = ce->CreateEntity(self_.lock());
121     } else {
122         ent = CreateDefaultEntity(*ecs_->ecs);
123     }
124     if (!CORE_NS::EntityUtil::IsValid(ent)) {
125         CORE_LOG_E("Failed to create entity [path=%s, id=%s]", BASE_NS::string(path).c_str(), id.ToString().c_str());
126         return nullptr;
127     }
128     ecs_->AddDefaultComponents(ent);
129     ecs_->SetNodeParentAndName(ent, EntityName(path), parent);
130     return ConstructNodeImpl(ent, node);
131 }
132 
CreateObject(META_NS::ObjectId id)133 META_NS::IObject::Ptr InternalScene::CreateObject(META_NS::ObjectId id)
134 {
135     auto& r = META_NS::GetObjectRegistry();
136     auto md = r.Create<META_NS::IMetadata>(META_NS::ClassId::Object);
137     md->AddProperty(META_NS::ConstructProperty<IInternalScene::Ptr>("Scene", self_.lock()));
138     auto object = r.Create<META_NS::IObject>(id, md);
139     if (!object) {
140         CORE_LOG_E("Failed to create scene object [id=%s]", id.ToString().c_str());
141         return nullptr;
142     }
143     if (auto acc = interface_cast<IEcsObjectAccess>(object)) {
144         CORE_NS::Entity ent;
145         if (auto ce = interface_pointer_cast<ICreateEntity>(object)) {
146             ent = ce->CreateEntity(self_.lock());
147         } else {
148             ent = CreateDefaultEntity(*ecs_->ecs);
149         }
150         if (!CORE_NS::EntityUtil::IsValid(ent)) {
151             CORE_LOG_E("Failed to create entity [id=%s]", id.ToString().c_str());
152             return nullptr;
153         }
154         auto eobj = ecs_->GetEcsObject(ent);
155         if (!acc->SetEcsObject(eobj)) {
156             return nullptr;
157         }
158     }
159     return object;
160 }
161 
ConstructNodeImpl(CORE_NS::Entity ent,INode::Ptr node) const162 INode::Ptr InternalScene::ConstructNodeImpl(CORE_NS::Entity ent, INode::Ptr node) const
163 {
164     auto acc = interface_cast<IEcsObjectAccess>(node);
165     if (!acc) {
166         return nullptr;
167     }
168     auto& r = META_NS::GetObjectRegistry();
169 
170     auto eobj = ecs_->GetEcsObject(ent);
171     if (!eobj) {
172         return nullptr;
173     }
174     AttachComponents(node, eobj, ent);
175 
176     if (!acc->SetEcsObject(eobj)) {
177         return nullptr;
178     }
179 
180     nodes_[ent] = node;
181     return node;
182 }
183 
DeducePrimaryNodeType(CORE_NS::Entity ent) const184 META_NS::ObjectId InternalScene::DeducePrimaryNodeType(CORE_NS::Entity ent) const
185 {
186     if (ecs_->cameraComponentManager->HasComponent(ent)) {
187         return ClassId::CameraNode;
188     }
189     if (ecs_->lightComponentManager->HasComponent(ent)) {
190         return ClassId::LightNode;
191     }
192     if (ecs_->textComponentManager && ecs_->textComponentManager->HasComponent(ent)) {
193         return ClassId::TextNode;
194     }
195     if (ecs_->renderMeshComponentManager->HasComponent(ent)) {
196         return ClassId::MeshNode;
197     }
198     return ClassId::Node;
199 }
200 
ConstructNode(CORE_NS::Entity ent,META_NS::ObjectId id) const201 INode::Ptr InternalScene::ConstructNode(CORE_NS::Entity ent, META_NS::ObjectId id) const
202 {
203     auto& r = META_NS::GetObjectRegistry();
204     if (!id.IsValid()) {
205         id = DeducePrimaryNodeType(ent);
206     }
207 
208     auto node = r.Create<INode>(id);
209     if (!node) {
210         CORE_LOG_E("Failed to create node object [id=%s]", id.ToString().c_str());
211         return nullptr;
212     }
213 
214     return ConstructNodeImpl(ent, node);
215 }
216 
CreateComponent(CORE_NS::IComponentManager * m,const IEcsObject::Ptr & ecsObject) const217 IComponent::Ptr InternalScene::CreateComponent(CORE_NS::IComponentManager* m, const IEcsObject::Ptr& ecsObject) const
218 {
219     auto& r = META_NS::GetObjectRegistry();
220     IComponent::Ptr comp;
221     if (auto fac = FindComponentFactory(m->GetUid())) {
222         comp = fac->CreateComponent(ecsObject);
223     } else {
224         auto md = r.Create<META_NS::IMetadata>(META_NS::ClassId::Object);
225         md->AddProperty(META_NS::ConstructProperty<BASE_NS::string>("Component", BASE_NS::string(m->GetName())));
226         comp = r.Create<IComponent>(ClassId::GenericComponent, md);
227         if (auto acc = interface_cast<IEcsObjectAccess>(comp)) {
228             if (!acc->SetEcsObject(ecsObject)) {
229                 return nullptr;
230             }
231         }
232     }
233     return comp;
234 }
235 
AttachComponents(const INode::Ptr & node,const IEcsObject::Ptr & ecsObject,CORE_NS::Entity ent) const236 void InternalScene::AttachComponents(
237     const INode::Ptr& node, const IEcsObject::Ptr& ecsObject, CORE_NS::Entity ent) const
238 {
239     auto& r = META_NS::GetObjectRegistry();
240     auto att = interface_cast<META_NS::IAttach>(node);
241     if (!att) {
242         return;
243     }
244 
245     auto attachments = att->GetAttachmentContainer(true);
246 
247     BASE_NS::vector<CORE_NS::IComponentManager*> managers;
248     ecs_->ecs->GetComponents(ent, managers);
249     for (auto m : managers) {
250         if (!attachments->FindByName(m->GetName())) {
251             if (auto comp = CreateComponent(m, ecsObject)) {
252                 att->Attach(comp);
253             } else {
254                 CORE_LOG_E("Failed to construct component for '%s'", BASE_NS::string(m->GetName()).c_str());
255             }
256         }
257     }
258 }
259 
FindNode(CORE_NS::Entity ent,META_NS::ObjectId id) const260 INode::Ptr InternalScene::FindNode(CORE_NS::Entity ent, META_NS::ObjectId id) const
261 {
262     if (ecs_->IsNodeEntity(ent)) {
263         auto path = ecs_->GetPath(ent);
264         if (!path.empty()) {
265             auto it = nodes_.find(ent);
266             if (it != nodes_.end()) {
267                 return it->second;
268             }
269             return ConstructNode(ent, id);
270         }
271     }
272 
273     CORE_LOG_W("Could not find entity: %" PRIu64, ent.id);
274     return nullptr;
275 }
276 
FindNode(BASE_NS::string_view path,META_NS::ObjectId id) const277 INode::Ptr InternalScene::FindNode(BASE_NS::string_view path, META_NS::ObjectId id) const
278 {
279     auto npath = NormalisePath(path);
280     auto n = ecs_->FindNode(npath);
281     if (n) {
282         auto it = nodes_.find(n->GetEntity());
283         if (it != nodes_.end()) {
284             return it->second;
285         }
286         return ConstructNode(n->GetEntity(), id);
287     }
288 
289     CORE_LOG_W("Could not find node: %s", BASE_NS::string(npath).c_str());
290     return nullptr;
291 }
292 
ReleaseChildNodes(const IEcsObject::Ptr & eobj)293 void InternalScene::ReleaseChildNodes(const IEcsObject::Ptr& eobj)
294 {
295     if (auto n = ecs_->GetNode(eobj->GetEntity())) {
296         for (auto&& c : n->GetChildren()) {
297             auto it = nodes_.find(c->GetEntity());
298             if (it != nodes_.end()) {
299                 auto nn = it->second;
300                 ReleaseNode(BASE_NS::move(nn), true);
301             }
302         }
303     }
304 }
305 
ReleaseNode(INode::Ptr && node,bool recursive)306 bool InternalScene::ReleaseNode(INode::Ptr&& node, bool recursive)
307 {
308     if (node) {
309         IEcsObject::Ptr eobj;
310         if (auto acc = interface_cast<IEcsObjectAccess>(node)) {
311             eobj = acc->GetEcsObject();
312         }
313         node.reset();
314         if (eobj) {
315             auto it = nodes_.find(eobj->GetEntity());
316             if (it != nodes_.end()) {
317                 // are we the only owner?
318                 if (it->second.use_count() == 1) {
319                     node = BASE_NS::move(it->second);
320                     nodes_.erase(it);
321                 }
322             }
323             if (recursive) {
324                 ReleaseChildNodes(eobj);
325             }
326             if (node) {
327                 ecs_->RemoveEcsObject(eobj);
328                 return true;
329             }
330         }
331     }
332     return false;
333 }
334 
RemoveNodesRecursively(CORE_NS::Entity ent)335 void InternalScene::RemoveNodesRecursively(CORE_NS::Entity ent)
336 {
337     if (auto n = ecs_->GetNode(ent)) {
338         for (auto&& c : n->GetChildren()) {
339             RemoveNodesRecursively(c->GetEntity());
340         }
341     }
342     nodes_.erase(ent);
343     ecs_->RemoveEntity(ent);
344 }
345 
RemoveNode(const INode::Ptr & node)346 bool InternalScene::RemoveNode(const INode::Ptr& node)
347 {
348     if (node) {
349         if (auto acc = interface_cast<IEcsObjectAccess>(node)) {
350             if (auto eobj = acc->GetEcsObject()) {
351                 RemoveNodesRecursively(eobj->GetEntity());
352                 return true;
353             }
354         }
355     }
356     return false;
357 }
358 
GetChildren(const IEcsObject::Ptr & obj) const359 BASE_NS::vector<INode::Ptr> InternalScene::GetChildren(const IEcsObject::Ptr& obj) const
360 {
361     BASE_NS::vector<INode::Ptr> res;
362     if (auto node = ecs_->GetNode(obj->GetEntity())) {
363         for (auto&& c : node->GetChildren()) {
364             if (auto n = FindNode(c->GetEntity(), {})) {
365                 res.push_back(n);
366             }
367         }
368     }
369     return res;
370 }
RemoveChild(const BASE_NS::shared_ptr<IEcsObject> & object,const BASE_NS::shared_ptr<IEcsObject> & child)371 bool InternalScene::RemoveChild(
372     const BASE_NS::shared_ptr<IEcsObject>& object, const BASE_NS::shared_ptr<IEcsObject>& child)
373 {
374     bool ret = false;
375     if (auto node = ecs_->GetNode(object->GetEntity())) {
376         if (auto childNode = ecs_->GetNode(child->GetEntity())) {
377             ret = node->RemoveChild(*childNode);
378             if (ret) {
379                 childNode->SetEnabled(false);
380             }
381         }
382     }
383     return ret;
384 }
AddChild(const BASE_NS::shared_ptr<IEcsObject> & object,const INode::Ptr & child,size_t index)385 bool InternalScene::AddChild(const BASE_NS::shared_ptr<IEcsObject>& object, const INode::Ptr& child, size_t index)
386 {
387     bool ret = false;
388     if (auto node = ecs_->GetNode(object->GetEntity())) {
389         if (auto acc = interface_cast<IEcsObjectAccess>(child)) {
390             auto ecsobj = acc->GetEcsObject();
391             if (auto childNode = ecs_->GetNode(ecsobj->GetEntity())) {
392                 if (node->InsertChild(index, *childNode)) {
393                     nodes_[ecsobj->GetEntity()] = child;
394                     childNode->SetEnabled(true);
395                     ret = true;
396                 }
397             }
398         }
399     }
400     return ret;
401 }
402 
GetScene() const403 BASE_NS::shared_ptr<IScene> InternalScene::GetScene() const
404 {
405     return scene_.lock();
406 }
407 
SchedulePropertyUpdate(const IEcsObject::Ptr & obj)408 void InternalScene::SchedulePropertyUpdate(const IEcsObject::Ptr& obj)
409 {
410     std::unique_lock lock { mutex_ };
411     syncs_[obj.get()] = obj;
412 }
413 
SyncProperties()414 void InternalScene::SyncProperties()
415 {
416     UpdateSyncProperties(false);
417 }
418 
UpdateSyncProperties(bool resetPending)419 bool InternalScene::UpdateSyncProperties(bool resetPending)
420 {
421     bool pending = false;
422     BASE_NS::unordered_map<void*, IEcsObject::WeakPtr> syncs;
423     {
424         std::unique_lock lock { mutex_ };
425         syncs = BASE_NS::move(syncs_);
426         pending = pendingRender_;
427         if (resetPending) {
428             pendingRender_ = false;
429         }
430     }
431 
432     for (auto&& v : syncs) {
433         if (auto o = v.second.lock()) {
434             o->SyncProperties();
435         }
436     }
437     return pending;
438 }
439 
Update(bool syncProperties)440 void InternalScene::Update(bool syncProperties)
441 {
442     using namespace std::chrono;
443     bool pending;
444     if (syncProperties) {
445         pending = UpdateSyncProperties(true);
446     } else {
447         std::unique_lock lock { mutex_ };
448         pending = pendingRender_;
449         pendingRender_ = false;
450     }
451 
452     ecs_->ecs->ProcessEvents();
453 
454     const auto currentTime =
455         static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
456 
457     if (firstTime_ == ~0u) {
458         previousFrameTime_ = firstTime_ = currentTime;
459     }
460     auto deltaTime = currentTime - previousFrameTime_;
461     constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
462     if (deltaTime > limitHz) {
463         deltaTime = limitHz; // clamp the time step to no longer than 15hz.
464     }
465     previousFrameTime_ = currentTime;
466     const uint64_t totalTime = currentTime - firstTime_;
467 
468     bool needsRender = ecs_->ecs->Update(totalTime, deltaTime);
469 
470     ecs_->ecs->ProcessEvents();
471 
472     if ((needsRender && mode_ != RenderMode::MANUAL) || pending) {
473         auto renderHandles = graphicsContext3D_->GetRenderNodeGraphs(*ecs_->ecs);
474         BASE_NS::vector<RENDER_NS::RenderHandleReference> customRenderHandles;
475         if (!customRenderNodeGraphs_.empty()) {
476             customRenderHandles.insert(customRenderHandles.begin(), renderHandles.begin(), renderHandles.end());
477             customRenderHandles.insert(
478                 customRenderHandles.end(), customRenderNodeGraphs_.begin(), customRenderNodeGraphs_.end());
479             renderHandles = move(customRenderHandles);
480         }
481         if (!renderHandles.empty()) {
482             // The scene needs to be rendered.
483             RENDER_NS::IRenderer& renderer = renderContext_->GetRenderer();
484             renderer.RenderDeferred(renderHandles);
485 
486             NotifyRenderingCameras();
487         }
488     }
489 }
490 
NotifyRenderingCameras()491 void InternalScene::NotifyRenderingCameras()
492 {
493     for (auto it = renderingCameras_.begin(); it != renderingCameras_.end();) {
494         if (auto c = it->lock()) {
495             c->NotifyRenderTargetChanged();
496             ++it;
497         } else {
498             it = renderingCameras_.erase(it);
499         }
500     }
501 }
502 
GetCameras() const503 BASE_NS::vector<ICamera::Ptr> InternalScene::GetCameras() const
504 {
505     BASE_NS::vector<ICamera::Ptr> ret;
506 
507     for (size_t i = 0; i != ecs_->cameraComponentManager->GetComponentCount(); ++i) {
508         if (auto n = interface_pointer_cast<ICamera>(
509                 FindNode(ecs_->cameraComponentManager->GetEntity(i), ClassId::CameraNode))) {
510             ret.push_back(n);
511         }
512     }
513 
514     return ret;
515 }
516 
GetAnimations() const517 BASE_NS::vector<META_NS::IAnimation::Ptr> InternalScene::GetAnimations() const
518 {
519     BASE_NS::vector<META_NS::IAnimation::Ptr> ret;
520 
521     for (size_t i = 0; i != ecs_->animationComponentManager->GetComponentCount(); ++i) {
522         auto ent = ecs_->animationComponentManager->GetEntity(i);
523         META_NS::IAnimation::Ptr anim;
524         if (auto it = animations_.find(ent); it != animations_.end()) {
525             anim = it->second.lock();
526         }
527         if (!anim) {
528             anim = META_NS::GetObjectRegistry().Create<META_NS::IAnimation>(ClassId::EcsAnimation);
529             if (auto acc = interface_cast<IEcsObjectAccess>(anim)) {
530                 acc->SetEcsObject(ecs_->GetEcsObject(ent));
531                 animations_[ent] = anim;
532             }
533         }
534         if (anim) {
535             ret.push_back(anim);
536         } else {
537             CORE_LOG_W("Failed to create EcsAnimation object");
538         }
539     }
540 
541     return ret;
542 }
543 
RegisterComponent(const BASE_NS::Uid & id,const IComponentFactory::Ptr & p)544 void InternalScene::RegisterComponent(const BASE_NS::Uid& id, const IComponentFactory::Ptr& p)
545 {
546     componentFactories_[id] = p;
547 }
548 
UnregisterComponent(const BASE_NS::Uid & id)549 void InternalScene::UnregisterComponent(const BASE_NS::Uid& id)
550 {
551     componentFactories_.erase(id);
552 }
553 
FindComponentFactory(const BASE_NS::Uid & id) const554 BASE_NS::shared_ptr<IComponentFactory> InternalScene::FindComponentFactory(const BASE_NS::Uid& id) const
555 {
556     auto it = componentFactories_.find(id);
557     return it != componentFactories_.end() ? it->second : nullptr;
558 }
559 
SyncProperty(const META_NS::IProperty::ConstPtr & p,META_NS::EngineSyncDirection dir)560 bool InternalScene::SyncProperty(const META_NS::IProperty::ConstPtr& p, META_NS::EngineSyncDirection dir)
561 {
562     META_NS::IEngineValue::Ptr value = GetEngineValueFromProperty(p);
563     if (!value) {
564         if (auto i = META_NS::GetFirstValueFromProperty<IConvertingValue>(p)) {
565             value = GetEngineValueFromProperty(i->GetTargetProperty());
566         }
567     }
568     META_NS::InterfaceUniqueLock valueLock { value };
569     return value && value->Sync(dir);
570 }
571 
AddRenderingCamera(const IInternalCamera::Ptr & camera)572 void InternalScene::AddRenderingCamera(const IInternalCamera::Ptr& camera)
573 {
574     for (auto&& v : renderingCameras_) {
575         if (camera == v.lock()) {
576             return;
577         }
578     }
579     renderingCameras_.push_back(camera);
580 }
RemoveRenderingCamera(const IInternalCamera::Ptr & camera)581 void InternalScene::RemoveRenderingCamera(const IInternalCamera::Ptr& camera)
582 {
583     for (auto it = renderingCameras_.begin(); it != renderingCameras_.end(); ++it) {
584         if (camera == it->lock()) {
585             renderingCameras_.erase(it);
586             return;
587         }
588     }
589 }
590 
SetRenderMode(RenderMode mode)591 bool InternalScene::SetRenderMode(RenderMode mode)
592 {
593     mode_ = mode;
594     ecs_->ecs->SetRenderMode(
595         mode == RenderMode::IF_DIRTY ? CORE_NS::IEcs::RENDER_IF_DIRTY : CORE_NS::IEcs::RENDER_ALWAYS);
596     return true;
597 }
GetRenderMode() const598 RenderMode InternalScene::GetRenderMode() const
599 {
600     return mode_;
601 }
RenderFrame()602 void InternalScene::RenderFrame()
603 {
604     std::unique_lock lock { mutex_ };
605     pendingRender_ = true;
606 }
HasPendingRender() const607 bool InternalScene::HasPendingRender() const
608 {
609     std::unique_lock lock { mutex_ };
610     return pendingRender_;
611 }
612 
MapHitResults(const BASE_NS::vector<CORE3D_NS::RayCastResult> & res,const RayCastOptions & options) const613 NodeHits InternalScene::MapHitResults(
614     const BASE_NS::vector<CORE3D_NS::RayCastResult>& res, const RayCastOptions& options) const
615 {
616     NodeHits result;
617     CORE3D_NS::ISceneNode* n = nullptr;
618     if (auto obj = interface_cast<IEcsObjectAccess>(options.node)) {
619         if (auto ecs = obj->GetEcsObject()) {
620             n = ecs_->GetNode(ecs->GetEntity());
621         }
622     }
623 
624     for (auto&& v : res) {
625         NodeHit h;
626         if (v.node && (!n || n->IsAncestorOf(*v.node))) {
627             h.node = FindNode(ecs_->GetPath(v.node), {});
628             h.distance = v.distance;
629             h.distanceToCenter = v.centerDistance;
630             h.position = v.worldPosition;
631             result.push_back(BASE_NS::move(h));
632         }
633     }
634     return result;
635 }
636 
CastRay(const BASE_NS::Math::Vec3 & pos,const BASE_NS::Math::Vec3 & dir,const RayCastOptions & options) const637 NodeHits InternalScene::CastRay(
638     const BASE_NS::Math::Vec3& pos, const BASE_NS::Math::Vec3& dir, const RayCastOptions& options) const
639 {
640     NodeHits result;
641     if (ecs_->picking) {
642         result = MapHitResults(ecs_->picking->RayCast(*ecs_->ecs, pos, dir, options.layerMask), options);
643     }
644     return result;
645 }
CastRay(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec2 & pos,const RayCastOptions & options) const646 NodeHits InternalScene::CastRay(
647     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec2& pos, const RayCastOptions& options) const
648 {
649     NodeHits result;
650     if (ecs_->picking) {
651         result = MapHitResults(
652             ecs_->picking->RayCastFromCamera(*ecs_->ecs, entity->GetEntity(), pos, options.layerMask), options);
653     }
654     return result;
655 }
ScreenPositionToWorld(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec3 & pos) const656 BASE_NS::Math::Vec3 InternalScene::ScreenPositionToWorld(
657     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec3& pos) const
658 {
659     BASE_NS::Math::Vec3 result;
660     if (ecs_->picking) {
661         result = ecs_->picking->ScreenToWorld(*ecs_->ecs, entity->GetEntity(), pos);
662     }
663     return result;
664 }
WorldPositionToScreen(const IEcsObject::ConstPtr & entity,const BASE_NS::Math::Vec3 & pos) const665 BASE_NS::Math::Vec3 InternalScene::WorldPositionToScreen(
666     const IEcsObject::ConstPtr& entity, const BASE_NS::Math::Vec3& pos) const
667 {
668     BASE_NS::Math::Vec3 result;
669     if (ecs_->picking) {
670         result = ecs_->picking->WorldToScreen(*ecs_->ecs, entity->GetEntity(), pos);
671     }
672     return result;
673 }
674 
AppendCustomRenderNodeGraph(RENDER_NS::RenderHandleReference rng)675 void InternalScene::AppendCustomRenderNodeGraph(RENDER_NS::RenderHandleReference rng)
676 {
677     customRenderNodeGraphs_.push_back(rng);
678 }
679 
SetSystemGraphUri(const BASE_NS::string & uri)680 void InternalScene::SetSystemGraphUri(const BASE_NS::string& uri)
681 {
682     systemGraph_ = uri;
683 }
684 
GetSystemGraphUri()685 BASE_NS::string InternalScene::GetSystemGraphUri()
686 {
687     return systemGraph_;
688 }
689 SCENE_END_NAMESPACE()
690