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