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 "scene_holder.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <inttypes.h>
21 #include <scene_plugin/api/material.h>
22 #include <scene_plugin/interface/intf_scene.h>
23 
24 #include <3d/ecs/components/environment_component.h>
25 #include <3d/ecs/components/local_matrix_component.h>
26 #include <3d/ecs/components/post_process_component.h>
27 #include <3d/ecs/components/render_configuration_component.h>
28 #include <3d/ecs/components/render_handle_component.h>
29 #include <3d/ecs/components/render_mesh_batch_component.h>
30 #include <3d/ecs/components/transform_component.h>
31 #include <3d/ecs/components/uri_component.h>
32 #include <3d/ecs/components/world_matrix_component.h>
33 #include <3d/ecs/systems/intf_render_preprocessor_system.h>
34 #include <3d/implementation_uids.h>
35 #include <3d/render/default_material_constants.h>
36 #include <3d/util/intf_mesh_builder.h>
37 #include <3d/util/intf_scene_util.h>
38 #include <base/util/uid_util.h>
39 #include <core/ecs/intf_system_graph_loader.h>
40 #include <core/intf_engine.h>
41 #include <core/plugin/intf_class_factory.h>
42 #include <render/device/intf_gpu_resource_manager.h>
43 #include <render/device/intf_shader_manager.h>
44 #include <render/intf_render_context.h>
45 #include <render/intf_renderer.h>
46 #include <render/util/intf_render_util.h>
47 
48 #include <meta/api/make_callback.h>
49 #include <meta/base/shared_ptr.h>
50 #include <meta/interface/intf_task_queue.h>
51 #include <meta/interface/intf_task_queue_registry.h>
52 
53 #include "asset_loader.h"
54 #include "asset_manager.h"
55 #include "ecs_util.h"
56 #include "entity_collection.h"
57 #include "intf_node_private.h"
58 #include "task_utils.h"
59 
60 // Initialize ecs on scene holder initialization or do it lazily when there's a scene to load
61 
62 using namespace BASE_NS;
63 using namespace CORE_NS;
64 using namespace CORE3D_NS;
65 using namespace RENDER_NS;
66 
67 using SCENE_NS::MakeTask;
68 
69 namespace {
70 
TickFrame(IEcs & ecs,uint64_t totalTime,uint64_t deltaTime)71 bool TickFrame(IEcs& ecs, uint64_t totalTime, uint64_t deltaTime)
72 {
73     // run garbage collection before updating the systems to ensure only valid entities/ components are available.
74     ecs.ProcessEvents();
75 
76     const bool needRender = ecs.Update(totalTime, deltaTime);
77 
78     // do gc also after the systems have been updated to ensure any deletes done by systems are effective
79     // and client doesn't see stale entities.
80     ecs.ProcessEvents();
81 
82     return needRender;
83 }
GetColorImageDesc(const uint32_t width,const uint32_t height)84 constexpr GpuImageDesc GetColorImageDesc(const uint32_t width, const uint32_t height)
85 {
86     GpuImageDesc resolveDesc;
87     resolveDesc.width = width;
88     resolveDesc.height = height;
89     resolveDesc.depth = 1;
90     resolveDesc.format = BASE_NS::Format::BASE_FORMAT_R8G8B8A8_SRGB;
91     resolveDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
92     resolveDesc.usageFlags =
93         ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT;
94     resolveDesc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
95     resolveDesc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
96     resolveDesc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
97     resolveDesc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
98     return resolveDesc;
99 }
100 
GetDepthImageDesc(const uint32_t width,const uint32_t height)101 constexpr GpuImageDesc GetDepthImageDesc(const uint32_t width, const uint32_t height)
102 {
103     GpuImageDesc resolveDesc;
104     resolveDesc.width = width;
105     resolveDesc.height = height;
106     resolveDesc.depth = 1;
107     resolveDesc.format = BASE_NS::Format::BASE_FORMAT_D16_UNORM;
108     resolveDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
109     resolveDesc.usageFlags = ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
110                              ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT;
111     resolveDesc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
112     resolveDesc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
113     resolveDesc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
114     resolveDesc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
115     return resolveDesc;
116 }
117 
118 static BASE_NS::string ROOTNODE_NAME = "rootNode_";
119 static BASE_NS::string ROOTNODE_PATH = "/" + ROOTNODE_NAME + "/";
120 
RemoveRootNodeFromPath(const BASE_NS::string_view & path)121 BASE_NS::string_view RemoveRootNodeFromPath(const BASE_NS::string_view& path)
122 {
123     if (path.starts_with(ROOTNODE_PATH)) {
124         return path.substr(ROOTNODE_PATH.length());
125     }
126 
127     if (path.starts_with("/")) {
128         return path.substr(1);
129     }
130 
131     return path;
132 }
133 } // namespace
134 
SceneHolder(META_NS::InstanceId uid,META_NS::IObjectRegistry & registry,const BASE_NS::shared_ptr<RENDER_NS::IRenderContext> & gc,META_NS::ITaskQueue::Ptr appQueue,META_NS::ITaskQueue::Ptr engineQueue)135 SceneHolder::SceneHolder(META_NS::InstanceId uid, META_NS::IObjectRegistry& registry,
136     const BASE_NS::shared_ptr<RENDER_NS::IRenderContext>& gc, META_NS::ITaskQueue::Ptr appQueue,
137     META_NS::ITaskQueue::Ptr engineQueue)
138     : instanceId_(uid), renderContext_(gc), appTaskQueue_(appQueue), engineTaskQueue_(engineQueue),
139       objectRegistry_(registry)
140 {}
141 
~SceneHolder()142 SceneHolder::~SceneHolder()
143 {
144     ResetScene(false);
145 }
146 
GetEcs()147 CORE_NS::IEcs::Ptr SceneHolder::GetEcs()
148 {
149     // once we offer Ecs to anyone, we cannot know it is intact
150     scenePrepared_ = false;
151     return ecs_;
152 }
153 
Initialize(WeakPtr me)154 void SceneHolder::Initialize(WeakPtr me)
155 {
156     me_ = me;
157     InitializeScene();
158 }
159 
Uninitialize()160 void SceneHolder::Uninitialize()
161 {
162     // Remove callbacks, these are no longer needed.
163     SetInitializeCallback({}, me_);
164     SetSceneLoadedCallback({}, me_);
165 
166     // Move processing to engine thread.
167     UninitializeScene();
168 }
SetRenderSize(uint32_t width,uint32_t height,uint64_t cameraHandle)169 void SceneHolder::SetRenderSize(uint32_t width, uint32_t height, uint64_t cameraHandle)
170 {
171     // Render size changed, schedule update engine thread.
172     UpdateViewportSize(width, height, cameraHandle);
173 }
174 
SetCameraTarget(const SCENE_NS::ICamera::Ptr & camera,BASE_NS::Math::UVec2 size,RENDER_NS::RenderHandleReference ref)175 void SceneHolder::SetCameraTarget(
176     const SCENE_NS::ICamera::Ptr& camera, BASE_NS::Math::UVec2 size, RENDER_NS::RenderHandleReference ref)
177 {
178     auto cameraEnt = interface_cast<SCENE_NS::IEcsObject>(camera)->GetEntity();
179 
180     CameraData::Ptr cd;
181     for (auto c : cameras_) {
182         if (c->entity == cameraEnt) {
183             cd = c;
184             break;
185         }
186     }
187     if (!cd) {
188         // invalid.
189         return;
190     }
191     cd->width = size.x;
192     cd->height = size.y;
193     if (!ref) {
194         cd->colorImage = {};
195         cd->ownsColorImage = true;
196         RecreateOutputTexture(cd);
197     } else {
198         cd->colorImage = ref;
199         cd->ownsColorImage = false;
200     }
201     cd->updateTargets = true;
202 }
203 
RequestReload()204 void SceneHolder::RequestReload()
205 {
206     LoadScene();
207 }
208 
Load(const BASE_NS::string & uri)209 void SceneHolder::Load(const BASE_NS::string& uri)
210 {
211     // Scene systems graph uri changed, schedule update to engine thread.
212     if (sceneUri_ != uri) {
213         sceneUri_ = uri;
214 
215         RequestReload();
216     }
217 }
218 
SetSystemGraphUri(const string & uri)219 void SceneHolder::SetSystemGraphUri(const string& uri)
220 {
221     // Scene systems graph uri changed, schedule update to engine thread.
222     if (uri != sceneSystemGraphUri_) {
223         sceneSystemGraphUri_ = uri;
224 
225         RequestReload();
226     }
227 }
228 
SetInitializeCallback(ISceneInitialized::Ptr callback,SceneHolder::WeakPtr weakMe)229 void SceneHolder::SetInitializeCallback(ISceneInitialized::Ptr callback, SceneHolder::WeakPtr weakMe)
230 {
231     // Schedule update of callback to engine thread.
232     sceneInitializedCallback_ = callback;
233 }
234 
SetSceneLoadedCallback(ISceneLoaded::Ptr callback,SceneHolder::WeakPtr weakMe)235 void SceneHolder::SetSceneLoadedCallback(ISceneLoaded::Ptr callback, SceneHolder::WeakPtr weakMe)
236 {
237     // Schedule update of callback to engine thread.
238     sceneLoadedCallback_ = callback;
239 }
240 
SetUninitializeCallback(ISceneUninitialized::Ptr callback,SceneHolder::WeakPtr weakMe)241 void SceneHolder::SetUninitializeCallback(ISceneUninitialized::Ptr callback, SceneHolder::WeakPtr weakMe)
242 {
243     // Schedule update of callback to engine thread.
244     sceneUninitializedCallback_ = callback;
245 }
246 
ActivateCamera(const Entity & cameraEntity) const247 void SceneHolder::ActivateCamera(const Entity& cameraEntity) const
248 {
249     if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
250         CORE_LOG_W("SceneHolder::ActivateCamera: Can not be activated. cameraEntity: %" PRIx64
251                    ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
252             cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
253         return;
254     }
255 
256     CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
257     cameraComponent.sceneFlags |= CameraComponent::ACTIVE_RENDER_BIT;
258     cameraComponentManager_->Set(cameraEntity, cameraComponent);
259 }
260 
DeactivateCamera(const Entity & cameraEntity) const261 void SceneHolder::DeactivateCamera(const Entity& cameraEntity) const
262 {
263     if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
264         CORE_LOG_W("SceneHolder::DeactivateCamera: Can not be deactivated. cameraEntity: %" PRIx64
265                    ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
266             cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
267         return;
268     }
269 
270     CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
271     cameraComponent.sceneFlags &= ~(CameraComponent::ACTIVE_RENDER_BIT /* | CameraComponent::MAIN_CAMERA_BIT*/);
272     cameraComponentManager_->Set(cameraEntity, cameraComponent);
273 }
274 
IsCameraActive(const Entity & cameraEntity) const275 bool SceneHolder::IsCameraActive(const Entity& cameraEntity) const
276 {
277     if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
278         CORE_LOG_W("SceneHolder::DeactivateCamera: Can not be deactivated. cameraEntity: %" PRIx64
279                    ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
280             cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
281         return false;
282     }
283 
284     CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
285     return cameraComponent.sceneFlags & (CameraComponent::ACTIVE_RENDER_BIT);
286 }
287 
InitializeScene()288 bool SceneHolder::InitializeScene()
289 {
290     graphicsContext3D_ = CreateInstance<CORE3D_NS::IGraphicsContext>(
291         *renderContext_->GetInterface<IClassFactory>(), UID_GRAPHICS_CONTEXT);
292     graphicsContext3D_->Init();
293 
294     picking_ = GetInstance<CORE3D_NS::IPicking>(*renderContext_->GetInterface<IClassRegister>(), UID_PICKING);
295 
296     // scene loading was attempted before initialization, retry now
297     if (loadSceneFailed_) {
298         loadSceneFailed_ = false;
299         RequestReload();
300     } else {
301         // business as usual, set up things according build time settings
302 #ifdef INITIALIZE_ECS_IMMEDIATELY
303         ResetScene(true);
304         scenePrepared_ = true;
305 #else
306         ResetScene(false);
307 #endif
308     }
309 
310     // This is one-time init.
311     return false;
312 }
313 
RenderCameras()314 BASE_NS::vector<CORE_NS::Entity> SceneHolder::RenderCameras()
315 {
316     // nobody has asked for updates, yet
317     if (!ecs_ /*|| isReadyForNewFrame_.empty()*/) {
318         return {};
319     }
320 
321     bool busy = false;
322     BASE_NS::vector<CORE_NS::Entity> activeCameras;
323     for (auto& camera : cameras_) {
324         if (!EntityUtil::IsValid(camera->entity))
325             continue;
326 
327         if (auto cc = cameraComponentManager_->Read(camera->entity)) {
328             if (cc->sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) {
329                 if (camera->updateTargets) {
330                     UpdateCameraRenderTarget(camera);
331                     camera->updateTargets = false;
332                 }
333                 activeCameras.push_back(camera->entity);
334             }
335         }
336     }
337     isRunningFrame_ = true;
338     // Tick frame. One camera could have static view while other is moving
339     IEcs* ecs = ecs_.get();
340     ecs->ProcessEvents();
341     using namespace std::chrono;
342     const auto currentTime =
343         static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
344     if (firstTime_ == ~0u) {
345         previousFrameTime_ = firstTime_ = currentTime;
346     }
347     auto deltaTime = currentTime - previousFrameTime_;
348     constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
349     if (deltaTime > limitHz) {
350         deltaTime = limitHz; // clampthe time step to no longer than 15hz.
351     }
352     previousFrameTime_ = currentTime;
353     const uint64_t totalTime = currentTime - firstTime_;
354     const bool needsRender = ecs->Update(totalTime, deltaTime);
355     ecs->ProcessEvents();
356     auto renderHandles = graphicsContext3D_->GetRenderNodeGraphs(*ecs_);
357 
358     if ((needsRender) && (!renderHandles.empty())) {
359         // The scene needs to be rendered.
360         RENDER_NS::IRenderer& renderer = renderContext_->GetRenderer();
361         renderer.RenderDeferred(renderHandles);
362     } else {
363         // did not render anything.
364         bool nr = needsRender;
365         activeCameras.clear();
366     }
367     isRunningFrame_ = false;
368 
369     if (requiresEventProcessing_) {
370         ProcessEvents();
371     }
372 
373     // Schedule new update to scene.
374     return activeCameras;
375 }
376 
UninitializeScene()377 bool SceneHolder::UninitializeScene()
378 {
379     ResetScene();
380 
381     if (ecs_) {
382         ecs_->Uninitialize();
383         ecs_.reset();
384     }
385 
386     if (sceneUninitializedCallback_) {
387         QueueApplicationTask(MakeTask(
388                                  [](auto callback) {
389                                      callback->Invoke();
390                                      return false;
391                                  },
392                                  sceneUninitializedCallback_),
393             false);
394     }
395 
396     sceneInitializedCallback_.reset();
397     sceneUpdatedCallback_.reset();
398     sceneUninitializedCallback_.reset();
399 
400     return false;
401 }
402 
ProcessEvents()403 void SceneHolder::ProcessEvents()
404 {
405     if (isRunningFrame_) {
406         requiresEventProcessing_ = true;
407         return;
408     }
409 
410     if (ecsListener_ && ecsListener_->IsCallbackActive()) {
411         requiresEventProcessing_ = true;
412         return;
413     }
414 
415     if (ecs_) {
416         ecs_->ProcessEvents();
417         requiresEventProcessing_ = false;
418     }
419 }
420 
CreateDefaultEcs()421 bool SceneHolder::CreateDefaultEcs()
422 {
423     if (!renderContext_) {
424         CORE_LOG_W("%s: Graphics contexts is not available, can not create ecs", __func__);
425         return false;
426     }
427 
428     auto& engine = renderContext_->GetEngine();
429 
430     ecs_ = engine.CreateEcs();
431     ecs_->SetRenderMode(renderMode_);
432 
433     if (!ecsListener_) {
434         ecsListener_ = BASE_NS::shared_ptr<SCENE_NS::EcsListener>(new SCENE_NS::EcsListener());
435     }
436     ecsListener_->SetEcs(ecs_);
437 
438     // Get systemGraphLoader factory from global plugin registry.
439     auto* factory = GetInstance<ISystemGraphLoaderFactory>(UID_SYSTEM_GRAPH_LOADER);
440     auto systemGraphLoader = factory->Create(engine.GetFileManager());
441 
442     // First try to load project-specific system graph.
443     auto result = sceneSystemGraphUri_.empty() ? false : systemGraphLoader->Load(sceneSystemGraphUri_, *ecs_).success;
444 
445     if (!result) {
446         // Fall back to default graph.
447         systemGraphLoader->Load("rofs3D://systemGraph.json", *ecs_);
448     }
449 
450     auto renderPreprocessorSystem = GetSystem<IRenderPreprocessorSystem>(*ecs_);
451 
452     string dataStorePrefix = "renderDataStore:" + GetUniqueName();
453 
454     auto& renderDataStoreManager = renderContext_->GetRenderDataStoreManager();
455 
456     auto sceneDataStore = dataStorePrefix + "RenderDataStoreDefaultScene";
457     auto cameraDataStore = dataStorePrefix + "RenderDataStoreDefaultCamera";
458     auto lightDataStore = dataStorePrefix + "RenderDataStoreDefaultLight";
459     auto materialDataStore = dataStorePrefix + "RenderDataStoreDefaultMaterial";
460     auto morphDataStore = dataStorePrefix + "RenderDataStoreMorph";
461 
462     if (renderPreprocessorSystem) {
463         IRenderPreprocessorSystem::Properties props;
464         props.dataStorePrefix = dataStorePrefix;
465         props.dataStoreScene = sceneDataStore;
466         props.dataStoreCamera = cameraDataStore;
467         props.dataStoreLight = lightDataStore;
468         props.dataStoreMaterial = materialDataStore;
469         props.dataStoreMorph = morphDataStore;
470 
471         *ScopedHandle<IRenderPreprocessorSystem::Properties>(renderPreprocessorSystem->GetProperties()) = props;
472     }
473 
474     if (auto callback = ecsInitializationCallback_.lock()) {
475         auto result = callback->Invoke(ecs_);
476         if (!result) {
477             CORE_LOG_W("Ecs initialization failed in the callback, expect trouble");
478         }
479     }
480 
481     ecs_->Initialize();
482 
483     animationComponentManager_ = CORE_NS::GetManager<CORE3D_NS::IAnimationComponentManager>(*ecs_);
484     cameraComponentManager_ = GetManager<CORE3D_NS::ICameraComponentManager>(*ecs_);
485     envComponentManager_ = GetManager<CORE3D_NS::IEnvironmentComponentManager>(*ecs_);
486     layerComponentManager_ = GetManager<CORE3D_NS::ILayerComponentManager>(*ecs_);
487     lightComponentManager_ = GetManager<CORE3D_NS::ILightComponentManager>(*ecs_);
488     materialComponentManager_ = GetManager<CORE3D_NS::IMaterialComponentManager>(*ecs_);
489     meshComponentManager_ = GetManager<CORE3D_NS::IMeshComponentManager>(*ecs_);
490     nameComponentManager_ = GetManager<CORE3D_NS::INameComponentManager>(*ecs_);
491     nodeComponentManager_ = GetManager<CORE3D_NS::INodeComponentManager>(*ecs_);
492     renderMeshComponentManager_ = GetManager<CORE3D_NS::IRenderMeshComponentManager>(*ecs_);
493     rhComponentManager_ = GetManager<CORE3D_NS::IRenderHandleComponentManager>(*ecs_);
494     transformComponentManager_ = GetManager<CORE3D_NS::ITransformComponentManager>(*ecs_);
495     uriComponentManager_ = GetManager<CORE3D_NS::IUriComponentManager>(*ecs_);
496 
497     if (animationComponentManager_) {
498         animationQuery_.reset(new CORE_NS::ComponentQuery());
499         animationQuery_->SetEcsListenersEnabled(true);
500         const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
501                                                              ComponentQuery::Operation::OPTIONAL },
502             { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL } };
503         animationQuery_->SetupQuery(*animationComponentManager_, operations);
504     }
505 
506     if (meshComponentManager_) {
507         meshQuery_.reset(new CORE_NS::ComponentQuery());
508         meshQuery_->SetEcsListenersEnabled(true);
509         const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
510                                                              ComponentQuery::Operation::OPTIONAL },
511             { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL } };
512         meshQuery_->SetupQuery(*meshComponentManager_, operations);
513     }
514 
515     if (materialComponentManager_) {
516         materialQuery_.reset(new CORE_NS::ComponentQuery());
517         materialQuery_->SetEcsListenersEnabled(true);
518         const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
519                                                              ComponentQuery::Operation::OPTIONAL },
520             { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL },
521             { *uriComponentManager_, ComponentQuery::Operation::OPTIONAL } };
522         materialQuery_->SetupQuery(*materialComponentManager_, operations);
523     }
524     nodeSystem_ = static_cast<CORE3D_NS::INodeSystem*>(ecs_->GetSystem(CORE3D_NS::INodeSystem::UID));
525     return true;
526 }
527 
CreateCamera(const BASE_NS::string & name,uint32_t flagBits)528 CORE_NS::Entity SceneHolder::CreateCamera(const BASE_NS::string& name, uint32_t flagBits)
529 {
530     return CreateCamera({}, name, flagBits);
531 }
532 
CreateCamera(const BASE_NS::string & path,const BASE_NS::string & name,uint32_t flagBits)533 CORE_NS::Entity SceneHolder::CreateCamera(const BASE_NS::string& path, const BASE_NS::string& name, uint32_t flagBits)
534 {
535     if (ecs_) {
536         auto pathWithoutRootNode = RemoveRootNodeFromPath(path);
537 
538         // Create camera. Scene util produces an invalid node so set up our camera from node system ourself
539         auto nodeSystem = GetSystem<INodeSystem>(*ecs_);
540         auto node = nodeSystem->CreateNode();
541         auto entity = node->GetEntity();
542 
543         CORE3D_NS::ISceneNode* parent = nullptr;
544         if (pathWithoutRootNode.empty()) {
545             parent = rootNode_;
546         } else {
547             parent = rootNode_->LookupNodeByPath(pathWithoutRootNode);
548         }
549 
550         CORE_ASSERT(parent);
551 
552         node->SetParent(*parent);
553         node->SetName(name);
554 
555         auto tcm = GetManager<ITransformComponentManager>(*ecs_);
556         TransformComponent tc;
557         tc.position = Math::Vec3(0.0f, 0.0f, 2.5f);
558         tc.rotation = {};
559         tcm->Set(entity, tc);
560 
561         CameraComponent cc;
562         cc.sceneFlags |= CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT;
563         cc.projection = CameraComponent::Projection::PERSPECTIVE;
564         cc.yFov = Math::DEG2RAD * 60.f;
565         cc.zNear = 0.1f;
566         cc.zFar = 100.f;
567         cc.sceneFlags |= flagBits;
568         cameraComponentManager_->Set(entity, cc);
569 
570         cameras_.emplace_back(CameraData::Create(entity));
571         return entity;
572     } else {
573         CORE_LOG_E("%s: Ecs not available, can not create camera %s", __func__, name.c_str());
574     }
575     return CORE_NS::Entity();
576 }
577 
SetDefaultCamera()578 void SceneHolder::SetDefaultCamera()
579 {
580     if (cameraComponentManager_) {
581         auto cameraCount = cameraComponentManager_->GetComponentCount();
582         while (cameraCount) {
583             --cameraCount;
584             // if the scene already contains main camera, respect it
585             if (cameraComponentManager_->Get(cameraComponentManager_->GetEntity(cameraCount)).sceneFlags &
586                 CameraComponent::MAIN_CAMERA_BIT) {
587                 auto entity = cameraComponentManager_->GetEntity(cameraCount);
588                 cameras_.emplace_back(CameraData::Create(entity));
589                 defaultCameraEntity_ = entity;
590                 SetMainCamera(entity);
591                 return;
592             }
593         }
594     }
595 }
596 
SetMainCamera(const Entity & entity)597 void SceneHolder::SetMainCamera(const Entity& entity)
598 {
599     if (cameras_.empty() || (mainCamera_ && entity == mainCamera_->entity)) {
600         return;
601     }
602 
603     if (mainCamera_ && cameraComponentManager_ && EntityUtil::IsValid(mainCamera_->entity)) {
604         bool isAlive = ecs_->GetEntityManager().IsAlive(mainCamera_->entity);
605         if (isAlive) {
606             // Mark previous main camera as inactive.
607             CameraComponent cameraComponent = cameraComponentManager_->Get(mainCamera_->entity);
608             cameraComponent.sceneFlags &= ~CameraComponent::MAIN_CAMERA_BIT;
609             cameraComponentManager_->Set(mainCamera_->entity, cameraComponent);
610         }
611     }
612 
613     mainCamera_ = {};
614 
615     for (auto& camera : cameras_) {
616         if (camera->entity == entity) {
617             mainCamera_ = camera;
618             break;
619         }
620     }
621 
622     if (!mainCamera_) {
623         if (EntityUtil::IsValid(entity)) {
624             CORE_LOG_W("%s: was not able to set camera for: %" PRIx64 " ", __func__, entity.id);
625         }
626         return;
627     }
628 
629     if (cameraComponentManager_ && EntityUtil::IsValid(mainCamera_->entity)) {
630         // Mark new camera as active.
631         CameraComponent cameraComponent = cameraComponentManager_->Get(mainCamera_->entity);
632         cameraComponent.sceneFlags |= CameraComponent::MAIN_CAMERA_BIT;
633         cameraComponentManager_->Set(mainCamera_->entity, cameraComponent);
634         UpdateViewportSize(mainCamera_->width, mainCamera_->height, mainCamera_->entity.id);
635     }
636 }
637 
AddCamera(const CORE_NS::Entity & entity)638 void SceneHolder::AddCamera(const CORE_NS::Entity& entity)
639 {
640     for (auto c : cameras_) {
641         if (c->entity == entity) {
642             return;
643         }
644     }
645     cameras_.emplace_back(CameraData::Create(entity));
646 }
647 
RemoveCamera(const CORE_NS::Entity & entity)648 void SceneHolder::RemoveCamera(const CORE_NS::Entity& entity)
649 {
650     auto it = std::find_if(cameras_.begin(), cameras_.end(), [entity](const auto& item) {
651         // Check if camera entities are the same.
652         return item->entity == entity;
653     });
654 
655     if (it != cameras_.end()) {
656         cameras_.erase(it);
657     }
658 }
659 
UpdateViewportSize(uint32_t width,uint32_t height,uint64_t cameraHandle)660 void SceneHolder::UpdateViewportSize(uint32_t width, uint32_t height, uint64_t cameraHandle)
661 {
662     CORE_LOG_D("%s: w: %u h: %u", __func__, width, height);
663     // these would be never valid as render target so use some default values to make sure that buffers are prepared
664     if (width == 0) {
665         width = 128; // 128 default width
666     }
667     if (height == 0) {
668         height = 128; // // 128 default height
669     }
670 
671     if (ecs_) {
672         if (cameraHandle == 0 && !cameras_.empty()) {
673             // short circuit defaut camera
674             cameraHandle = cameras_.front()->entity.id;
675         }
676 
677         // Make sure that render target will be updated
678         // ToDo: Clean this up to select the correct camera instance
679         CameraData::Ptr camera;
680 
681         for (auto& c : cameras_) {
682             if (c->entity.id == cameraHandle) {
683                 camera = c;
684                 break;
685             }
686         }
687         if (!camera) {
688             return;
689         }
690         if (!camera->ownsColorImage) {
691             // we don't own the bitmap so.
692             return;
693         }
694 
695         camera->width = width;
696         camera->height = height;
697         RecreateOutputTexture(camera);
698 
699         if (!EntityUtil::IsValid(camera->entity)) {
700             return;
701         }
702         camera->updateTargets = true;
703         ecs_->RequestRender();
704     }
705 }
706 
RecreateOutputTexture(CameraData::Ptr camera)707 void SceneHolder::RecreateOutputTexture(CameraData::Ptr camera)
708 {
709     if ((renderContext_) && (camera)) {
710         if (camera->ownsColorImage) {
711             camera->colorImage = renderContext_->GetDevice().GetGpuResourceManager().Create(
712                 GetColorImageDesc(camera->width, camera->height));
713 #ifdef SCENE_PLUGIN_CREATE_IMPLICIT_DEPTH_TARGET
714             camera->depthImage = renderContext_->GetDevice().GetGpuResourceManager().Create(
715                 GetDepthImageDesc(camera->width, camera->height));
716 #endif
717         }
718     }
719 }
720 
UpdateCameraRenderTarget(CameraData::Ptr camera)721 bool SceneHolder::UpdateCameraRenderTarget(CameraData::Ptr camera)
722 {
723     if (!EntityUtil::IsValid(camera->entity))
724         return false;
725 
726     if (auto cc = cameraComponentManager_->Write(camera->entity)) {
727         auto& em = ecs_->GetEntityManager();
728         cc->renderResolution[0] = static_cast<float>(camera->width);
729         cc->renderResolution[1] = static_cast<float>(camera->height);
730         cc->customColorTargets = { GetOrCreateEntityReference(em, *rhComponentManager_, camera->colorImage) };
731         if (camera->depthImage) {
732             cc->customDepthTarget = GetOrCreateEntityReference(em, *rhComponentManager_, camera->depthImage);
733         }
734         if (cc->sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) {
735             // please render also.
736             return true;
737         }
738     }
739     // no render.
740     return false;
741 }
742 
ResetScene(bool initialize)743 void SceneHolder::ResetScene(bool initialize)
744 {
745     bool wasScenePrepared = scenePrepared_;
746     scenePrepared_ = false;
747     if (wasScenePrepared && initialize) {
748         return;
749     }
750 
751     SetMainCamera({});
752     cameras_.clear();
753 
754     animations_.clear();
755 
756     // Release resource data.
757     gltfResourceData_ = {};
758     sceneEntity_ = {};
759 
760     // Release default camera.
761     defaultCameraEntity_ = {};
762 
763     // Release scene
764     scene_ = {};
765     assetManager_ = {};
766 
767     // Release scene root.
768     rootNode_ = {};
769 
770     // fully recreate ECS if requested
771     if (ecs_) {
772         cameraComponentManager_ = {};
773         meshComponentManager_ = {};
774         nameComponentManager_ = {};
775         nodeComponentManager_ = {};
776         meshQuery_ = {};
777         materialQuery_ = {};
778         animationQuery_ = {};
779         ecsListener_->Reset();
780         ecs_->Uninitialize();
781         ecs_.reset();
782     }
783 
784     if (sceneUninitializedCallback_) {
785         QueueApplicationTask(MakeTask(
786                                  [](auto callback) {
787                                      callback->Invoke();
788                                      return false;
789                                  },
790                                  sceneUninitializedCallback_),
791             false);
792     }
793 
794     if (initialize && CreateDefaultEcs()) {
795         // Create new root node.
796         CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
797         rootNode_ = nodeSystem.CreateNode();
798         rootNode_->SetName(ROOTNODE_NAME);
799         if (nodeComponentManager_) {
800             nodeComponentManager_->Create(rootNode_->GetEntity());
801         }
802         scene_ = SCENE_NS::IEntityCollection::Ptr { new SCENE_NS::EntityCollection(*ecs_, "scene", {}) };
803 
804         // it seems that having our root entity as a part of loaded entify has no significant effect on
805         // anything Presumably it is ok to keep it out of the serialization auto entityRef =
806 
807         rootNode_->SetEnabled(true);
808 
809         assetManager_ =
810             SCENE_NS::IAssetManager::Ptr { new SCENE_NS::AssetManager(*renderContext_, *graphicsContext3D_) };
811     }
812 }
813 
SetSceneSystemGraph(const BASE_NS::string & uri)814 void SceneHolder::SetSceneSystemGraph(const BASE_NS::string& uri)
815 {
816     if (uri != sceneSystemGraphUri_) {
817         sceneSystemGraphUri_ = uri;
818         scenePrepared_ = false;
819         if (scene_) {
820             // reload with new graph
821             LoadScene();
822 
823         } else if (sceneLoadedCallback_) {
824             QueueApplicationTask(MakeTask(
825                                      [](auto sceneLoadedCallback) {
826                                          if (sceneLoadedCallback) {
827                                              sceneLoadedCallback->Invoke(SCENE_NS::IScene::SCENE_STATUS_UNINITIALIZED);
828                                          }
829                                          return false;
830                                      },
831                                      sceneLoadedCallback_),
832                 false);
833         }
834     }
835 }
836 
LoadScene(const BASE_NS::string & uri)837 void SceneHolder::LoadScene(const BASE_NS::string& uri)
838 {
839     // ToDo: LoadScene shoud deal with this, but currently triggers a problem when we swap between instances
840     if (sceneUri_ == uri) {
841         if (sceneLoadedCallback_) {
842             bool haveEcs = (ecs_ == nullptr);
843             QueueApplicationTask(MakeTask(
844                                      [haveEcs](auto sceneLoadedCallback) {
845                                          if (sceneLoadedCallback) {
846                                              sceneLoadedCallback->Invoke(
847                                                  haveEcs ? SCENE_NS::IScene::SCENE_STATUS_READY
848                                                          : SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED);
849                                          }
850                                          return false;
851                                      },
852                                      sceneLoadedCallback_),
853                 false);
854         }
855         return;
856     }
857     sceneUri_ = uri;
858     LoadScene();
859 }
860 
861 static constexpr BASE_NS::string_view KDUMMY_STRING { "!#&/dummy" };
862 
IntrospectNodeless()863 void SceneHolder::IntrospectNodeless()
864 {
865 #ifndef NDEBUG
866     Entity dummy {};
867     FindMesh(KDUMMY_STRING, KDUMMY_STRING, dummy);
868     FindMaterial(KDUMMY_STRING, KDUMMY_STRING, dummy);
869 #endif // !NDEBUG
870 
871     RemoveUriComponentsFromMeshes();
872     ResolveAnimations();
873 }
874 
GetEntityId(const CORE_NS::Entity & entity,BASE_NS::string_view & entityName,SCENE_NS::IEntityCollection & collection,BASE_NS::string_view backupCollection,CORE3D_NS::INameComponentManager & nameComponentManager)875 bool GetEntityId(const CORE_NS::Entity& entity, BASE_NS::string_view& entityName,
876     SCENE_NS::IEntityCollection& collection, BASE_NS::string_view backupCollection,
877     CORE3D_NS::INameComponentManager& nameComponentManager)
878 {
879     if (EntityUtil::IsValid(entity)) {
880         entityName = collection.GetUniqueIdentifierRecursive(entity);
881         if (!entityName.empty() && entityName != "/") {
882             return true;
883         } else {
884             if (auto readHandle = nameComponentManager.Read(entity)) {
885                 entityName = readHandle->name;
886                 collection.AddEntityToSubcollection(backupCollection, entityName, entity, true);
887                 auto gltfCollectionIx = collection.GetSubCollectionIndex(backupCollection);
888                 if (auto gltfCollection = collection.GetSubCollection(gltfCollectionIx)) {
889                     entityName = gltfCollection->GetUniqueIdentifier(entity);
890                     return true;
891                 }
892             } else {
893                 // ToDo: we could store entity id even it did not have name component
894                 CORE_LOG_W("%s: entity missing from collections", __func__);
895             }
896         }
897     }
898     return false;
899 }
900 
ExtractQueryResults(CORE_NS::ComponentQuery & query,SCENE_NS::IEntityCollection & collection,BASE_NS::string_view backupCollection,BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> & result,CORE3D_NS::INameComponentManager & nameComponentManager)901 void ExtractQueryResults(CORE_NS::ComponentQuery& query, SCENE_NS::IEntityCollection& collection,
902     BASE_NS::string_view backupCollection, BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>>& result,
903     CORE3D_NS::INameComponentManager& nameComponentManager)
904 {
905     query.Execute();
906     auto results = query.GetResults();
907     for (auto& row : results) {
908         BASE_NS::string_view id;
909         if (GetEntityId(row.entity, id, collection, backupCollection, nameComponentManager)) {
910             result->push_back(id);
911         }
912     }
913 }
914 
ListMaterialNames()915 BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> SceneHolder::ListMaterialNames()
916 {
917     BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> ret { new BASE_NS::vector<BASE_NS::string_view> };
918     if (materialQuery_ && scene_) {
919         ExtractQueryResults(*materialQuery_, *scene_.get(), "GLTF_Materials", ret, *nameComponentManager_);
920     }
921     return ret;
922 }
923 
ListMeshNames()924 BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> SceneHolder::ListMeshNames()
925 {
926     BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> ret { new BASE_NS::vector<BASE_NS::string_view> };
927     if (meshQuery_ && scene_) {
928         ExtractQueryResults(*meshQuery_, *scene_.get(), "GLTF_Meshes", ret, *nameComponentManager_);
929     }
930     return ret;
931 }
932 
RemoveUriComponentsFromMeshes()933 void SceneHolder::RemoveUriComponentsFromMeshes()
934 {
935     meshQuery_->Execute();
936     auto meshes = meshQuery_->GetResults();
937 
938     SCENE_PLUGIN_VERBOSE_LOG("found %zu meshes", meshes.size());
939 
940     // Remove uri component from meshes, since it causes issues with prefab loading.
941     // The gltf importer shares the meshes between collections, if they have
942     // similar uri.
943     // However, this is not desired behavior, because scene-overridden property
944     // values will propagate to future prefab instances (e.g. material).
945     for (auto& mesh : meshes) {
946         if (uriComponentManager_->HasComponent(mesh.entity)) {
947             uriComponentManager_->Destroy(mesh.entity);
948         }
949     }
950 }
951 
FindMesh(const BASE_NS::string_view name,const BASE_NS::string_view fullPath,Entity & entity)952 bool SceneHolder::FindMesh(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
953 {
954     if (ecs_) {
955         entity = scene_->GetEntityRecursive(fullPath);
956         if (CORE_NS::EntityUtil::IsValid(entity)) {
957             return true;
958         }
959 
960         meshQuery_->Execute();
961         auto meshes = meshQuery_->GetResults();
962 
963         SCENE_PLUGIN_VERBOSE_LOG("found %zu meshes", meshes.size());
964 
965 #ifdef NDEBUG
966         if (name == KDUMMY_STRING) {
967             return false;
968         }
969 #endif
970 
971         for (auto&& mesh : meshes) {
972             bool effectivelyEnabled = false;
973             if (auto readHandle = nodeComponentManager_->Read(mesh.components[1])) {
974                 effectivelyEnabled = readHandle->effectivelyEnabled;
975             }
976             BASE_NS::string entityName;
977             if (auto readHandle = nameComponentManager_->Read(mesh.components[2])) {
978                 entityName = readHandle->name;
979             }
980             SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
981             if (name == entityName || fullPath == entityName) {
982                 entity = mesh.entity;
983                 return true;
984             }
985         }
986         // Could not find the mesh with given the name, try if it has a node
987         const auto& root = nodeSystem_->GetRootNode();
988         if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
989             entity = ecsNode->GetEntity();
990             return true;
991         }
992     }
993     return false;
994 }
995 
GetResourceId(CORE_NS::Entity entity)996 BASE_NS::string SceneHolder::GetResourceId(CORE_NS::Entity entity)
997 {
998     BASE_NS::string result;
999 
1000     if (scene_) {
1001         result = scene_->GetUniqueIdentifierRecursive(entity);
1002     }
1003     return result;
1004 }
1005 
FindMaterial(const BASE_NS::string_view name,const BASE_NS::string_view fullPath,Entity & entity)1006 bool SceneHolder::FindMaterial(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
1007 {
1008     if (ecs_) {
1009         entity = scene_->GetEntityRecursive(fullPath);
1010         if (CORE_NS::EntityUtil::IsValid(entity)) {
1011             return true;
1012         }
1013 
1014         materialQuery_->Execute();
1015         auto materials = materialQuery_->GetResults();
1016 
1017         SCENE_PLUGIN_VERBOSE_LOG("found %zu materials", materials.size());
1018 
1019 #ifdef NDEBUG
1020         if (name == KDUMMY_STRING) {
1021             return false;
1022         }
1023 #endif
1024 
1025         for (auto&& material : materials) {
1026             bool effectivelyEnabled = false;
1027             if (auto readHandle = nodeComponentManager_->Read(material.components[1])) {
1028                 effectivelyEnabled = readHandle->effectivelyEnabled;
1029             }
1030             BASE_NS::string entityName;
1031             if (auto readHandle = nameComponentManager_->Read(material.components[2])) {
1032                 entityName = readHandle->name;
1033             }
1034             SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
1035             if (name == entityName) {
1036                 entity = material.entity;
1037                 return true;
1038             }
1039             if (auto readHandle = uriComponentManager_->Read(material.components[3])) {
1040                 entityName = readHandle->uri;
1041             }
1042 
1043             if (!entityName.empty()) {
1044                 if (name == entityName || fullPath == entityName) {
1045                     entity = material.entity;
1046                     return true;
1047                 }
1048             }
1049         }
1050         // Could not find the material with the given name, try if it has a node
1051         const auto& root = nodeSystem_->GetRootNode();
1052         if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
1053             entity = ecsNode->GetEntity();
1054             return true;
1055         }
1056         // Desperate measures, to be rectified
1057         if (auto created = rootNode_->LookupNodeByPath(fullPath)) {
1058             entity = created->GetEntity();
1059             return true;
1060         }
1061     }
1062     return false;
1063 }
1064 
FindAnimation(const BASE_NS::string_view name,const BASE_NS::string_view fullPath,Entity & entity)1065 bool SceneHolder::FindAnimation(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
1066 {
1067     if (ecs_) {
1068         if (!animations_.empty()) {
1069             size_t ix = name.rfind(":");
1070             if (ix != BASE_NS::string_view::npos && ix != name.size() - 1) {
1071                 char* dummy = nullptr;
1072                 auto entityId = strtoll(name.substr(ix + 1).data(), &dummy, 16);
1073                 if (animations_.find(entityId) != animations_.cend()) {
1074                     entity.id = entityId;
1075                     return true;
1076                 }
1077             }
1078 
1079             for (auto&& animation : animations_) {
1080                 if (META_NS::GetValue(interface_pointer_cast<META_NS::INamed>(animation.second)->Name()) == name) {
1081                     entity.id = animation.first;
1082                     return true;
1083                 }
1084             }
1085         } else {
1086             animationQuery_->Execute();
1087             auto animations = animationQuery_->GetResults();
1088 
1089             SCENE_PLUGIN_VERBOSE_LOG("found %zu animations", animations.size());
1090 
1091 #ifdef NDEBUG
1092             if (name == KDUMMY_STRING) {
1093                 return false;
1094             }
1095 #endif
1096 
1097             for (auto&& animation : animations) {
1098                 bool effectivelyEnabled = false;
1099                 if (auto readHandle = nodeComponentManager_->Read(animation.components[1])) {
1100                     effectivelyEnabled = readHandle->effectivelyEnabled;
1101                 }
1102                 BASE_NS::string entityName;
1103                 if (auto readHandle = nameComponentManager_->Read(animation.components[2])) {
1104                     entityName = readHandle->name;
1105                 }
1106                 SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
1107                 if (name == entityName || fullPath == entityName) {
1108                     entity = animation.entity;
1109                     return true;
1110                 }
1111             }
1112             // Could not find the animation with given the name, try if it has a node
1113             const auto& root = nodeSystem_->GetRootNode();
1114             if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
1115                 entity = ecsNode->GetEntity();
1116                 return true;
1117             }
1118         }
1119     }
1120     return false;
1121 }
1122 
ResolveAnimations()1123 void SceneHolder::ResolveAnimations()
1124 {
1125     if (ecs_) {
1126         animationQuery_->Execute();
1127         auto animations = animationQuery_->GetResults();
1128 
1129         SCENE_PLUGIN_VERBOSE_LOG("%s, found %zu animations", __func__, animations.size());
1130 
1131         for (auto&& animation : animations) {
1132             if (animations_.find(animation.entity.id) == animations_.cend()) {
1133                 animations_[animation.entity.id] =
1134                     GetObjectRegistry().Create<SCENE_NS::IEcsAnimation>(SCENE_NS::ClassId::EcsAnimation);
1135                 if (auto ecsProxyIf =
1136                         interface_pointer_cast<SCENE_NS::IEcsProxyObject>(animations_[animation.entity.id])) {
1137                     ecsProxyIf->SetCommonListener(GetCommonEcsListener());
1138                 }
1139                 animations_[animation.entity.id]->SetEntity(*ecs_, animation.entity);
1140             }
1141         }
1142     }
1143 }
1144 
UpdateAttachments(SCENE_NS::IEcsObject::Ptr & ecsObject)1145 void SceneHolder::UpdateAttachments(SCENE_NS::IEcsObject::Ptr& ecsObject)
1146 {
1147     if (ecs_) {
1148         auto entity = ecsObject->GetEntity();
1149         if (EntityUtil::IsValid(entity)) {
1150             for (auto&& animation : animations_) {
1151                 if (animation.second->GetRootEntity() == entity) {
1152                     ecsObject->AddAttachment(animation.second->GetEntity());
1153                 }
1154             }
1155         }
1156     }
1157 }
1158 
1159 // This could be highly inefficient, in most cases we should have a clue of resource type
FindResource(const BASE_NS::string_view name,const BASE_NS::string_view fullPath,Entity & entity)1160 bool SceneHolder::FindResource(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
1161 {
1162     if (ecs_ && scene_) {
1163         if (FindAnimation(name, fullPath, entity) || FindMaterial(name, fullPath, entity) ||
1164             FindMesh(name, fullPath, entity)) {
1165             return true;
1166         }
1167 
1168         // traverse through scene collection
1169         for (size_t ix = 0; ix < scene_->GetSubCollectionCount(); ix++) {
1170             if (const auto& subcollection = scene_->GetSubCollection(ix); subcollection->GetUri() == fullPath) {
1171                 // the assumption is that we do not have to dig deeper
1172                 if (subcollection->GetEntityCount() > 0) {
1173                     entity = subcollection->GetEntity(0);
1174                     return true;
1175                 }
1176             }
1177         }
1178 
1179         // Try finding an existing resource with an uri. This is needed e.g. for the images loaded from an glTF
1180         // file where the uri does not point to an actual image file but the resource is just a entity with uri in
1181         // ECS.
1182         if (renderMeshComponentManager_ && uriComponentManager_) {
1183             for (size_t i = 0; i < uriComponentManager_->GetComponentCount(); ++i) {
1184                 const Entity currentEntity =
1185                     uriComponentManager_->GetEntity(static_cast<IComponentManager::ComponentId>(i));
1186                 if (ecs_->GetEntityManager().IsAlive(currentEntity)) {
1187                     if (auto uriComponent = uriComponentManager_->Read(currentEntity);
1188                         uriComponent && uriComponent->uri == fullPath) {
1189                         if (renderMeshComponentManager_->HasComponent(currentEntity)) {
1190                             entity = currentEntity;
1191                             return true;
1192                         }
1193                     }
1194                 }
1195             }
1196         }
1197     }
1198 
1199     return false;
1200 }
1201 
GetImageEntity(CORE_NS::Entity material,size_t index,CORE_NS::Entity & entity)1202 bool SceneHolder::GetImageEntity(CORE_NS::Entity material, size_t index, CORE_NS::Entity& entity)
1203 {
1204     bool ret { false };
1205     if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(material)) {
1206         if (auto handle = materialComponentManager_->Read(material)) {
1207             entity = handle->textures[index].image;
1208             ret = true;
1209         }
1210     }
1211 
1212     return ret;
1213 }
1214 
GetRenderHandleUri(const RENDER_NS::RenderHandle & handle,BASE_NS::string & uriString)1215 bool SceneHolder::GetRenderHandleUri(const RENDER_NS::RenderHandle& handle, BASE_NS::string& uriString)
1216 {
1217     if (ecs_) {
1218         auto& renderUtil = graphicsContext3D_->GetRenderContext().GetRenderUtil();
1219 
1220         size_t index { 0 };
1221         while (auto handleReference = rhComponentManager_->GetRenderHandleReference(index)) {
1222             if (handleReference.GetHandle() == handle) {
1223                 auto& renderUtil = graphicsContext3D_->GetRenderContext().GetRenderUtil();
1224                 const auto desc = renderUtil.GetRenderHandleDesc(handleReference);
1225                 if (desc.type == RenderHandleType::GPU_IMAGE && !desc.name.empty()) {
1226                     // Note: assuming that the name is the image uri. Ignore the name if not in uri format.
1227                     if (desc.name.find(":/") != BASE_NS::string::npos) {
1228                         uriString = desc.name;
1229                         return true;
1230                     }
1231                 }
1232             }
1233             index++;
1234         }
1235     }
1236     return false;
1237 }
1238 
CreatePostProcess()1239 CORE_NS::Entity SceneHolder::CreatePostProcess()
1240 {
1241     CORE_NS::Entity entity;
1242     if (ecs_) {
1243         auto pm = CORE_NS::GetManager<CORE3D_NS::IPostProcessComponentManager>(*ecs_);
1244         entity = ecs_->GetEntityManager().Create();
1245         // createComponent
1246         pm->Create(entity);
1247     }
1248     return entity;
1249 }
1250 
CreateRenderConfiguration()1251 CORE_NS::Entity SceneHolder::CreateRenderConfiguration()
1252 {
1253     CORE_NS::Entity entity;
1254     if (ecs_) {
1255         entity = ecs_->GetEntityManager().Create();
1256 
1257         auto rcm = CORE_NS::GetManager<CORE3D_NS::IRenderConfigurationComponentManager>(*ecs_);
1258         rcm->Create(entity);
1259     }
1260     return entity;
1261 }
1262 
SetRenderHandle(const CORE_NS::Entity & target,const CORE_NS::Entity & source)1263 void SceneHolder::SetRenderHandle(const CORE_NS::Entity& target, const CORE_NS::Entity& source)
1264 {
1265     if (ecs_) {
1266         if (auto sourceHandle = rhComponentManager_->GetRenderHandleReference(source)) {
1267             if (!rhComponentManager_->HasComponent(target)) {
1268                 rhComponentManager_->Create(target);
1269             }
1270             if (auto handle = rhComponentManager_->Write(target)) {
1271                 handle->reference = sourceHandle;
1272             }
1273         }
1274     }
1275 }
1276 
GetEntityUri(const CORE_NS::Entity & entity,BASE_NS::string & uriString)1277 bool SceneHolder::GetEntityUri(const CORE_NS::Entity& entity, BASE_NS::string& uriString)
1278 {
1279     bool ret { false };
1280     if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
1281         if (auto handle = uriComponentManager_->Read(entity)) {
1282             uriString = BASE_NS::string(handle->uri.data(), handle->uri.size());
1283             ret = true;
1284         }
1285     }
1286 
1287     if (!ret) {
1288         // Special handling for render handles (automatically loaded images in the ecs are now just render handles
1289         // with a name containing the uri).
1290         auto handle = rhComponentManager_->GetRenderHandleReference(entity);
1291         if (handle) {
1292             auto& renderUtil = renderContext_->GetRenderUtil();
1293             const auto desc = renderUtil.GetRenderHandleDesc(handle);
1294             if (desc.type == RenderHandleType::GPU_IMAGE && !desc.name.empty()) {
1295                 // Note: assuming that the name is the image uri. Ignore the name if not in uri format.
1296                 if (desc.name.find(":/") != BASE_NS::string::npos) {
1297                     uriString = desc.name;
1298                     ret = true;
1299                 }
1300             }
1301         }
1302     }
1303 
1304     return ret;
1305 }
GetImageHandle(const CORE_NS::Entity & entity,RENDER_NS::RenderHandleReference & handle,RENDER_NS::GpuImageDesc & desc)1306 bool SceneHolder::GetImageHandle(
1307     const CORE_NS::Entity& entity, RENDER_NS::RenderHandleReference& handle, RENDER_NS::GpuImageDesc& desc)
1308 {
1309     if (rhComponentManager_->HasComponent(entity)) {
1310         handle = rhComponentManager_->GetRenderHandleReference(entity);
1311         desc = renderContext_->GetDevice().GetGpuResourceManager().GetImageDescriptor(handle);
1312         return true;
1313     }
1314     return false;
1315 }
1316 
SetEntityUri(const CORE_NS::Entity & entity,const BASE_NS::string & uriString)1317 bool SceneHolder::SetEntityUri(const CORE_NS::Entity& entity, const BASE_NS::string& uriString)
1318 {
1319     bool ret { false };
1320     if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
1321         if (!uriComponentManager_->HasComponent(entity)) {
1322             uriComponentManager_->Create(entity);
1323         }
1324 
1325         if (auto handle = uriComponentManager_->Write(entity)) {
1326             handle->uri = uriString;
1327             ret = true;
1328         }
1329     }
1330 
1331     return ret;
1332 }
1333 
GetEntityName(const CORE_NS::Entity & entity,BASE_NS::string & nameString)1334 bool SceneHolder::GetEntityName(const CORE_NS::Entity& entity, BASE_NS::string& nameString)
1335 {
1336     bool ret { false };
1337     if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
1338         if (auto handle = nameComponentManager_->Read(entity)) {
1339             nameString = BASE_NS::string(handle->name.data(), handle->name.size());
1340             ret = true;
1341         }
1342     }
1343 
1344     return ret;
1345 }
1346 
GetEntityByUri(BASE_NS::string_view uriString)1347 CORE_NS::Entity SceneHolder::GetEntityByUri(BASE_NS::string_view uriString)
1348 {
1349     for (size_t i = 0; i < uriComponentManager_->GetComponentCount(); ++i) {
1350         const Entity entity = uriComponentManager_->GetEntity(static_cast<IComponentManager::ComponentId>(i));
1351         if (ecs_->GetEntityManager().IsAlive(entity)) {
1352             if (auto uriComponent = uriComponentManager_->Read(entity);
1353                 uriComponent && uriComponent->uri == uriString) {
1354                 return entity;
1355             }
1356         }
1357     }
1358 
1359     return {};
1360 }
1361 
ResolveNodeFullPath(CORE3D_NS::ISceneNode * node,BASE_NS::string & path)1362 bool ResolveNodeFullPath(CORE3D_NS::ISceneNode* node, BASE_NS::string& path)
1363 {
1364     if (node) {
1365         path = node->GetName();
1366         while ((node = node->GetParent())) {
1367             path.insert(0, "/");
1368             auto name = node->GetName();
1369             path.insert(0, name.data(), name.size());
1370         }
1371     }
1372     return (!path.empty());
1373 }
1374 
ResolveNodeFullPath(CORE_NS::IEcs & ecs,const CORE_NS::Entity & entity)1375 BASE_NS::string ResolveNodeFullPath(CORE_NS::IEcs& ecs, const CORE_NS::Entity& entity)
1376 {
1377     CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(ecs);
1378     BASE_NS::string ret;
1379     ResolveNodeFullPath(nodeSystem.GetNode(entity), ret);
1380     return ret;
1381 }
1382 
LoadScene()1383 void SceneHolder::LoadScene()
1384 {
1385     // Reset scene to default.
1386     CORE_LOG_I("Loading scene: '%s'", sceneUri_.c_str());
1387     uint32_t loadingStatus = SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED;
1388     bool replacedRoot { false };
1389 
1390     while (true) {
1391         if (sceneUri_.empty()) {
1392             ResetScene();
1393             loadingStatus = SCENE_NS::IScene::SCENE_STATUS_UNINITIALIZED;
1394             break;
1395         }
1396 
1397         auto params = SCENE_NS::PathUtil::GetUriParameters(sceneUri_);
1398         auto ite = params.find("target");
1399         if (!scene_ || ite == params.end() || ite->second.empty()) {
1400             ResetScene(true);
1401             replacedRoot = true;
1402         } else {
1403             CORE_LOG_I("Load into scene: %s", ite->second.c_str());
1404         }
1405 
1406         // If ecs initializing failed, report it back and return
1407         if (!ecs_) {
1408             break;
1409         }
1410 
1411         if (assetManager_) {
1412             if ((sceneUri_ != "scene://empty") && !assetManager_->LoadAsset(*scene_, sceneUri_, "project://")) {
1413                 CORE_LOG_E("Loading scene %s failed", sceneUri_.c_str());
1414                 ResetScene();
1415                 break;
1416             } else { // ToDo: This is currently done also when a node is added to container, so no need to do it
1417                      // here
1418                 // Rearrange scene to have a concrete common root node, this will be more important for prefabs
1419                 CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
1420                 auto& root = nodeSystem.GetRootNode();
1421 
1422                 // ToDo: should this fetch the named root node instead
1423                 auto ourRoot = root.GetChildren().at(0);
1424                 ourRoot->SetEnabled(true);
1425 
1426                 auto ite = root.GetChildren().begin() + 1;
1427                 while (ite != root.GetChildren().end()) {
1428                     (*ite)->SetParent(*ourRoot);
1429                     ite = root.GetChildren().begin() + 1;
1430                 }
1431             }
1432 
1433             // Loading might have cached some assets (in case there are multiple
1434             // instances). Scene widget will not need them after loading so clear the
1435             // cache.
1436             if (replacedRoot) {
1437                 assetManager_->ClearCache();
1438             }
1439         }
1440         if (sceneUri_ != "scene://empty") {
1441             // Set default camera.
1442             SetDefaultCamera();
1443         }
1444         // ask synchronous update
1445         RenderCameras();
1446         loadingStatus = SCENE_NS::IScene::SCENE_STATUS_READY;
1447         break;
1448     }
1449 
1450     // If ecs initialization fails, all we can do is to retry loading later
1451     if (!ecs_) {
1452         loadSceneFailed_ = true;
1453 
1454         if (sceneLoadedCallback_) {
1455             QueueApplicationTask(MakeTask(
1456                                      [](auto sceneLoadedCallback, auto loadingStatus) {
1457                                          if (sceneLoadedCallback)
1458                                              sceneLoadedCallback->Invoke(loadingStatus);
1459                                          return false;
1460                                      },
1461                                      sceneLoadedCallback_, loadingStatus),
1462                 false);
1463         }
1464         return;
1465     }
1466 
1467     // make sure that components get updated
1468     ProcessEvents();
1469 
1470     IntrospectNodeless();
1471     // Call back the app thread, notify that the graphics and ecs are ready. This
1472     // is not quite true, though
1473     if (ecs_ && replacedRoot && sceneInitializedCallback_) {
1474         BASE_NS::string id { rootNode_->GetName() };
1475         BASE_NS::string cameraId = ResolveNodeFullPath(*ecs_, defaultCameraEntity_);
1476         QueueApplicationTask(MakeTask(
1477                                  [](auto sceneInitializedCallback, auto id, auto cameraId) {
1478                                      if (sceneInitializedCallback) {
1479                                          sceneInitializedCallback->Invoke(id, cameraId);
1480                                      }
1481                                      return false;
1482                                  },
1483                                  sceneInitializedCallback_, id, cameraId),
1484             false);
1485     } else if (sceneLoadedCallback_) { // Call back the app thread, notify that new scene is loaded
1486         QueueApplicationTask(MakeTask(
1487                                  [](auto sceneLoadedCallback, auto loadingStatus) {
1488                                      if (sceneLoadedCallback) {
1489                                          sceneLoadedCallback->Invoke(loadingStatus);
1490                                      }
1491                                      return false;
1492                                  },
1493                                  sceneLoadedCallback_, loadingStatus),
1494             false);
1495     }
1496 }
1497 
ChangeCamera(SCENE_NS::ICamera::Ptr camera)1498 void SceneHolder::ChangeCamera(SCENE_NS::ICamera::Ptr camera)
1499 {
1500     if (auto cameraObject = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) {
1501         auto entity = cameraObject->GetEntity();
1502         if (EntityUtil::IsValid(entity)) {
1503             SetMainCamera(entity);
1504         }
1505     }
1506 }
1507 
logNodes(const CORE3D_NS::ISceneNode & node,BASE_NS::string path)1508 void logNodes(const CORE3D_NS::ISceneNode& node, BASE_NS::string path)
1509 {
1510     if (!path.empty() && path.back() != '/') {
1511         path.append("/");
1512     }
1513     if (!node.GetName().empty()) {
1514         path.append(node.GetName());
1515     } else {
1516         path.append("[");
1517         path.append(BASE_NS::to_string(node.GetEntity().id));
1518         path.append("]");
1519     }
1520     CORE_LOG_I("%s", path.c_str());
1521 
1522     for (const auto child : node.GetChildren())
1523         logNodes(*child, path);
1524 }
1525 
SaveScene(const BASE_NS::string & fileName)1526 void SceneHolder::SaveScene(const BASE_NS::string& fileName)
1527 {
1528     assetManager_->SaveJsonEntityCollection(*scene_.get(), fileName.empty() ? sceneUri_ : fileName, "file://");
1529 
1530     // Verbose logs, to be suppressed at some point
1531     CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
1532     logNodes(nodeSystem.GetRootNode(), "/");
1533     IntrospectNodeless();
1534 }
1535 
CreateNode(const BASE_NS::string & name)1536 CORE3D_NS::ISceneNode* SceneHolder::CreateNode(const BASE_NS::string& name)
1537 {
1538     return CreateNode({}, name);
1539 }
1540 
CreateNode(const BASE_NS::string & path,const BASE_NS::string & name)1541 CORE3D_NS::ISceneNode* SceneHolder::CreateNode(const BASE_NS::string& path, const BASE_NS::string& name)
1542 {
1543     if (ecs_) {
1544         auto pathWithoutRootNode = RemoveRootNodeFromPath(path);
1545 
1546         CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
1547 
1548         CORE3D_NS::ISceneNode* parent = nullptr;
1549         if (pathWithoutRootNode.empty()) {
1550             parent = rootNode_;
1551         } else {
1552             parent = rootNode_->LookupNodeByPath(pathWithoutRootNode);
1553         }
1554 
1555         CORE_ASSERT(parent);
1556 
1557         auto instanceRoot = nodeSystem.CreateNode();
1558         instanceRoot->SetName(name);
1559         instanceRoot->SetParent(*parent);
1560         return instanceRoot;
1561     } else {
1562         CORE_LOG_E("%s: Ecs not available, can not create node %s", __func__, name.c_str());
1563     }
1564 
1565     return nullptr;
1566 }
1567 
CreateMaterial(const BASE_NS::string & name)1568 CORE_NS::Entity SceneHolder::CreateMaterial(const BASE_NS::string& name)
1569 {
1570     if (ecs_) {
1571         auto entity = ecs_->GetEntityManager().Create();
1572 
1573         RenameEntity(entity, name);
1574 
1575         materialComponentManager_->Create(entity);
1576         scene_->AddEntityToSubcollection("created_materials", name, entity);
1577         ProcessEvents();
1578         return entity;
1579 
1580     } else {
1581         CORE_LOG_E("%s: Ecs not available, can not create material %s", __func__, name.c_str());
1582     }
1583 
1584     return {};
1585 }
1586 
RenameEntity(CORE_NS::Entity entity,const BASE_NS::string & name)1587 void SceneHolder::RenameEntity(CORE_NS::Entity entity, const BASE_NS::string& name)
1588 {
1589     if (ecs_) {
1590         // Name Component
1591         if (!nameComponentManager_->HasComponent(entity)) {
1592             nameComponentManager_->Create(entity);
1593         }
1594         if (auto nameHandle = nameComponentManager_->Write(entity)) {
1595             nameHandle->name = name;
1596         }
1597 
1598         // Root level entity collection item
1599         if (BASE_NS::string_view prevName = scene_->GetUniqueIdentifier(entity); !prevName.empty()) {
1600             scene_->SetUniqueIdentifier(name, scene_->GetEntity(prevName));
1601         } else if (nodeComponentManager_->HasComponent(entity)) {
1602             if (auto ecsNode = nodeSystem_->GetNode(entity)) {
1603                 if (const auto& children = ecsNode->GetChildren(); children.size()) {
1604                     if (auto ix = scene_->GetSubCollectionIndexByRoot(children[0]->GetEntity()); ix != -1) {
1605                         scene_->GetSubCollection(ix)->SetUri(name);
1606                     }
1607                 }
1608             }
1609         }
1610         // Experimentals: Subcollection root (will not traverse further, the rest should go through normal property
1611         // serialization)
1612     }
1613 }
1614 
1615 // Clone the entity, reference will be stored
CloneEntity(CORE_NS::Entity entity,const BASE_NS::string & name,bool storeWithUniqueId)1616 CORE_NS::Entity SceneHolder::CloneEntity(CORE_NS::Entity entity, const BASE_NS::string& name, bool storeWithUniqueId)
1617 {
1618     CORE_NS::Entity ret {};
1619 
1620     if (ecs_ && scene_) {
1621         ret = ecs_->GetEntityManager().Create();
1622         CORE_NS::CloneComponents(*ecs_, entity, *ecs_, ret);
1623         RenameEntity(ret, name);
1624         // when cloning, we trust that implementation uses unique name so no padding required
1625         scene_->AddEntityToSubcollection("cloned_entities", name, ret, storeWithUniqueId);
1626     }
1627     return ret;
1628 }
1629 
DestroyEntity(CORE_NS::Entity entity)1630 void SceneHolder::DestroyEntity(CORE_NS::Entity entity)
1631 {
1632     // Destroy created materials & meshes here.
1633     auto meshCollectionIndex = scene_->GetSubCollectionIndex("GLTF_Meshes");
1634     if (meshCollectionIndex != -1) {
1635         auto meshCollection = scene_->GetSubCollection(meshCollectionIndex);
1636         if (meshCollection->Contains(entity)) {
1637             auto ref = meshCollection->GetReference(entity);
1638             meshCollection->RemoveEntity(ref);
1639         }
1640     }
1641 
1642     auto materialCollectionIndex = scene_->GetSubCollectionIndex("GLTF_Materials");
1643     if (materialCollectionIndex != -1) {
1644         auto materialCollection = scene_->GetSubCollection(materialCollectionIndex);
1645         if (materialCollection->Contains(entity)) {
1646             auto ref = materialCollection->GetReference(entity);
1647             materialCollection->RemoveEntity(ref);
1648         }
1649     }
1650     scene_->RemoveEntityRecursive(entity);
1651 }
1652 
SetEntityActive(CORE_NS::Entity entity,bool active)1653 void SceneHolder::SetEntityActive(CORE_NS::Entity entity, bool active)
1654 {
1655     ecs_->GetEntityManager().SetActive(entity, active);
1656 }
1657 
ReparentEntity(CORE_NS::Entity entity,const BASE_NS::string & parentPath,size_t index)1658 bool SceneHolder::ReparentEntity(CORE_NS::Entity entity, const BASE_NS::string& parentPath, size_t index)
1659 {
1660     auto& root = nodeSystem_->GetRootNode();
1661 
1662     auto node = nodeSystem_->GetNode(entity);
1663     if (!node) {
1664         CORE_LOG_W("SceneHolder::ReparentEntity, Failed to find node from entity.");
1665         return false;
1666     }
1667 
1668     auto parentNode = root.LookupNodeByPath(parentPath);
1669     if (!parentNode) {
1670         if (parentPath == "/" || parentPath.empty()) {
1671             parentNode = &root;
1672         } else {
1673             CORE_LOG_W("SceneHolder::ReparentEntity, Failed to find parent node '%s'", parentPath.c_str());
1674             return false;
1675         }
1676     }
1677 
1678     if (parentNode != node->GetParent()) {
1679         if (index != SIZE_MAX) {
1680             parentNode->InsertChild(index, *node);
1681         } else {
1682             parentNode->AddChild(*node);
1683         }
1684     }
1685 
1686     return true;
1687 }
1688 
ReparentEntity(const BASE_NS::string & parentPath,const BASE_NS::string & name)1689 const CORE3D_NS::ISceneNode* SceneHolder::ReparentEntity(const BASE_NS::string& parentPath, const BASE_NS::string& name)
1690 {
1691     if (ecs_) {
1692         const auto& root = nodeSystem_->GetRootNode();
1693         auto ecsNode = root.LookupNodeByPath(name);
1694         auto parentNode = root.LookupNodeByPath(parentPath);
1695 
1696         if (!ecsNode && parentNode) {
1697             if (ecsNode = parentNode->LookupNodeByPath(name); !ecsNode) {
1698                 CORE_LOG_W("Could not find: '%s', tried root and parent '%s'", name.c_str(), parentPath.c_str());
1699             }
1700         } else if (parentNode && parentNode != ecsNode) { // prefabs may get have their path pointing them self
1701                                                           // before they are positioned into scene
1702             const_cast<CORE3D_NS::ISceneNode*>(ecsNode)->SetParent(*parentNode);
1703             SCENE_PLUGIN_VERBOSE_LOG("reparenting '%s' to '%s'", name.c_str(), parentPath.c_str());
1704         } else if (!parentPath.empty() && parentPath != "/") {
1705             CORE_LOG_W("Could not find parent '%s'", parentPath.c_str());
1706             // Even parent is not found, we can still activate the bindings, still we could
1707             // reschedule retry here
1708         }
1709         return ecsNode;
1710     }
1711     return {};
1712 }
1713 
SetMesh(CORE_NS::Entity targetEntity,CORE_NS::Entity mesh)1714 void SceneHolder::SetMesh(CORE_NS::Entity targetEntity, CORE_NS::Entity mesh)
1715 {
1716     if (ecs_) {
1717         if (EntityUtil::IsValid(targetEntity) && EntityUtil::IsValid(mesh)) {
1718             // ToDo: should perhaps generate render mesh component for entity if it does not exist yet?
1719 
1720             if (!renderMeshComponentManager_->HasComponent(targetEntity)) {
1721                 renderMeshComponentManager_->Create(targetEntity);
1722             }
1723 
1724             if (auto handle = renderMeshComponentManager_->Write(targetEntity)) {
1725                 handle->mesh = mesh;
1726             }
1727         }
1728     }
1729 }
1730 
GetMaterial(CORE_NS::Entity meshEntity,int64_t submeshIndex)1731 CORE_NS::Entity SceneHolder::GetMaterial(CORE_NS::Entity meshEntity, int64_t submeshIndex)
1732 {
1733     CORE_NS::Entity material;
1734     if (ecs_) {
1735         if (EntityUtil::IsValid(meshEntity)) {
1736             if (auto handle = meshComponentManager_->Read(meshEntity)) {
1737                 if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
1738                     material = handle->submeshes[submeshIndex].material;
1739                 }
1740             }
1741         }
1742     }
1743     return material;
1744 }
1745 
GetMaterialName(CORE_NS::Entity meshEntity,int64_t submeshIndex)1746 BASE_NS::string_view SceneHolder::GetMaterialName(CORE_NS::Entity meshEntity, int64_t submeshIndex)
1747 {
1748     BASE_NS::string_view entityName;
1749     auto entity = GetMaterial(meshEntity, submeshIndex);
1750 
1751     if (!GetEntityId(entity, entityName, *scene_.get(), "GLTF_Materials", *nameComponentManager_)) {
1752         CORE_LOG_W("%s: could not find material", __func__);
1753     }
1754 
1755     return entityName;
1756 }
1757 
GetMeshName(CORE_NS::Entity referringEntity)1758 BASE_NS::string_view SceneHolder::GetMeshName(CORE_NS::Entity referringEntity)
1759 {
1760     BASE_NS::string_view entityName;
1761 
1762     if (EntityUtil::IsValid(referringEntity)) {
1763         CORE_NS::Entity meshEntity;
1764 
1765         if (renderMeshComponentManager_->HasComponent(referringEntity)) {
1766             if (auto handle = renderMeshComponentManager_->Read(referringEntity)) {
1767                 meshEntity = handle->mesh;
1768             }
1769         } else {
1770             CORE_LOG_W("%s: could not find mesh from entity", __func__);
1771         }
1772         if (!GetEntityId(meshEntity, entityName, *scene_.get(), "GLTF_Meshes", *nameComponentManager_)) {
1773             CORE_LOG_W("%s: could not find valid mesh", __func__);
1774         }
1775     }
1776     return entityName;
1777 }
1778 
SetMaterial(CORE_NS::Entity targetEntity,CORE_NS::Entity material,int64_t submeshIndex)1779 void SceneHolder::SetMaterial(CORE_NS::Entity targetEntity, CORE_NS::Entity material, int64_t submeshIndex)
1780 {
1781     if (ecs_) {
1782         if (EntityUtil::IsValid(targetEntity)) {
1783             // ToDo: should perhaps generate mesh component for entity if it does not exist yet?
1784 
1785             if (auto handle = meshComponentManager_->Write(targetEntity)) {
1786                 if (submeshIndex == -1) {
1787                     for (auto&& submesh : handle->submeshes) {
1788                         submesh.material = material;
1789                     }
1790                 } else if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
1791                     handle->submeshes[submeshIndex].material = material;
1792                 }
1793             }
1794         }
1795     }
1796 }
1797 
BindUIBitmap(SCENE_NS::IBitmap::Ptr bitmap,bool createNew)1798 CORE_NS::EntityReference SceneHolder::BindUIBitmap(SCENE_NS::IBitmap::Ptr bitmap, bool createNew)
1799 {
1800     if (ecs_) {
1801         BASE_NS::string uri;
1802         RENDER_NS::RenderHandleReference imageHandle {};
1803 
1804         // Need two things, uri
1805         if (auto uriBmp = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap)) {
1806             uri = uriBmp->Uri()->GetValue();
1807         } else {
1808             uri = interface_pointer_cast<META_NS::IObjectInstance>(bitmap)->GetInstanceId().ToString();
1809         }
1810 
1811         // And concrete handle to data
1812         if (auto lumeBmp = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap)) {
1813             imageHandle = lumeBmp->GetRenderHandle();
1814         }
1815 
1816         if (imageHandle) {
1817             // check if we have existing resource
1818             CORE_NS::Entity existing;
1819             if (FindResource(uri, uri, existing)) {
1820                 auto hande = rhComponentManager_->Get(existing);
1821                 hande.reference = imageHandle;
1822                 rhComponentManager_->Set(existing, hande);
1823 
1824                 return ecs_->GetEntityManager().GetReferenceCounted(existing);
1825             }
1826 
1827             if (!createNew) {
1828                 return {};
1829             }
1830 
1831             // if not, create new one
1832             EntityReference entity = ecs_->GetEntityManager().CreateReferenceCounted();
1833 
1834             nameComponentManager_->Create(entity);
1835             auto component = nameComponentManager_->Get(entity);
1836             component.name = uri;
1837             nameComponentManager_->Set(entity, component);
1838 
1839             // Not sure if we should do this, somehow we need to keep the entity alive
1840             // with proper uri it could be found afterwards
1841             auto& subcollection = scene_->AddSubCollection(uri, "bitmap://");
1842             subcollection.AddEntity(entity);
1843 
1844             // Or this. We should perhaps use URI component more
1845             rhComponentManager_->Create(entity);
1846             auto hande = rhComponentManager_->Get(entity);
1847             hande.reference = imageHandle;
1848             rhComponentManager_->Set(entity, hande);
1849             return entity;
1850         }
1851     }
1852 
1853     return {};
1854 }
1855 
SetTexture(size_t index,CORE_NS::Entity targetEntity,CORE_NS::EntityReference imageEntity)1856 void SceneHolder::SetTexture(size_t index, CORE_NS::Entity targetEntity, CORE_NS::EntityReference imageEntity)
1857 {
1858     if (ecs_) {
1859         if (auto handle = materialComponentManager_->Write(targetEntity)) {
1860             handle->textures[index].image = imageEntity;
1861         }
1862     }
1863 }
1864 
ResolveSamplerUri(SCENE_NS::ITextureInfo::SamplerId samplerId)1865 BASE_NS::string_view ResolveSamplerUri(SCENE_NS::ITextureInfo::SamplerId samplerId)
1866 {
1867     switch (samplerId) {
1868         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_NEAREST_REPEAT:
1869             return "engine://CORE_DEFAULT_SAMPLER_NEAREST_REPEAT";
1870         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP:
1871             return "engine://CORE_DEFAULT_SAMPLER_NEAREST_CLAMP";
1872         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_REPEAT:
1873             return "engine://CORE_DEFAULT_SAMPLER_LINEAR_REPEAT";
1874         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP:
1875             return "engine://CORE_DEFAULT_SAMPLER_LINEAR_CLAMP";
1876         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT:
1877             return "engine://CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT";
1878         case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP:
1879             return "engine://CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP";
1880         default:
1881             CORE_LOG_W("%s: unable to find sampler uri for: %d", __func__, samplerId);
1882     }
1883 
1884     return "";
1885 }
1886 
1887 static constexpr size_t ENGINE_URI_PREFIX_LEN = BASE_NS::string_view("engine://").size();
1888 
GetShader(CORE_NS::Entity materialEntity,ShaderType type)1889 SCENE_NS::IShader::Ptr SceneHolder::GetShader(CORE_NS::Entity materialEntity, ShaderType type)
1890 {
1891     // Resolve render handle from material.
1892     if (!ecs_) {
1893         return {};
1894     }
1895 
1896     if (!EntityUtil::IsValid(materialEntity)) {
1897         return {};
1898     }
1899 
1900     RENDER_NS::RenderHandleReference shaderHandleRef;
1901 
1902     EntityReference shaderEntityRef {};
1903     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
1904         if (type == ShaderType::MATERIAL_SHADER) {
1905             shaderEntityRef = readHandle->materialShader.shader;
1906         } else if (type == ShaderType::DEPTH_SHADER) {
1907             shaderEntityRef = readHandle->depthShader.shader;
1908         }
1909     }
1910 
1911     if (shaderEntityRef) {
1912         auto rh = rhComponentManager_->GetRenderHandleReference(shaderEntityRef);
1913         if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
1914             auto uri = GetHandleUri(rh, HANDLE_TYPE_SHADER);
1915             if (!uri.empty()) {
1916                 auto shader = SCENE_NS::Shader();
1917 
1918                 auto shaderInterface = interface_pointer_cast<SCENE_NS::IShader>(shader);
1919                 SetValue(shaderInterface->Uri(), uri);
1920 
1921                 return shader;
1922             }
1923         }
1924     }
1925 
1926     return {};
1927 }
1928 
GetGraphicsState(CORE_NS::Entity materialEntity,ShaderType type)1929 SCENE_NS::IGraphicsState::Ptr SceneHolder::GetGraphicsState(CORE_NS::Entity materialEntity, ShaderType type)
1930 {
1931     // Resolve render handle from material.
1932     if (!ecs_) {
1933         return {};
1934     }
1935 
1936     if (!EntityUtil::IsValid(materialEntity)) {
1937         return {};
1938     }
1939 
1940     RENDER_NS::RenderHandleReference shaderHandleRef;
1941 
1942     EntityReference stateEntityRef {};
1943     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
1944         if (type == ShaderType::MATERIAL_SHADER) {
1945             stateEntityRef = readHandle->materialShader.graphicsState;
1946         } else if (type == ShaderType::DEPTH_SHADER) {
1947             stateEntityRef = readHandle->depthShader.graphicsState;
1948         }
1949     }
1950 
1951     if (stateEntityRef) {
1952         auto rh = rhComponentManager_->GetRenderHandleReference(stateEntityRef);
1953         if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
1954             auto uri = GetHandleUri(rh);
1955             if (!uri.empty()) {
1956                 auto state = SCENE_NS::GraphicsState();
1957 
1958                 auto interface = interface_pointer_cast<SCENE_NS::IGraphicsState>(state);
1959 
1960                 // The uri contains either .shader or .shadergs.
1961                 BASE_NS::string extension = ".shadergs";
1962                 if (uri.find(extension) == BASE_NS::string::npos) {
1963                     extension = ".shader";
1964                 }
1965 
1966                 // Split the uri to uri and variant.
1967                 auto ix = uri.find_last_of(extension);
1968                 if (ix != BASE_NS::string_view::npos && ix < uri.size() - 1) {
1969                     SetValue(interface->Uri(), BASE_NS::string(uri.substr(0, ix + 1)));
1970                     SetValue(interface->Variant(), BASE_NS::string(uri.substr(ix + 1)));
1971                     SCENE_PLUGIN_VERBOSE_LOG("Got graphics state: %s variant: %s",
1972                         META_NS::GetValue(interface->Uri()).c_str(), META_NS::GetValue(interface->Variant()).c_str());
1973                 } else {
1974                     SetValue(interface->Uri(), uri);
1975                     SetValue(interface->Variant(), "");
1976                 }
1977 
1978                 if (auto shRef = interface_cast<ISceneHolderRef>(state)) {
1979                     shRef->SetSceneHolder(me_);
1980                     shRef->SetIndex(type);
1981                 }
1982 
1983                 return state;
1984             }
1985         }
1986     }
1987 
1988     return {};
1989 }
1990 
SetGraphicsState(CORE_NS::Entity materialEntity,ShaderType type,const RENDER_NS::GraphicsState & state)1991 void SceneHolder::SetGraphicsState(
1992     CORE_NS::Entity materialEntity, ShaderType type, const RENDER_NS::GraphicsState& state)
1993 {
1994     if (!ecs_) {
1995         return;
1996     }
1997 
1998     if (!EntityUtil::IsValid(materialEntity)) {
1999         return;
2000     }
2001 
2002     CORE_NS::EntityReference entityRef;
2003     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
2004         if (type == ShaderType::MATERIAL_SHADER) {
2005             entityRef = readHandle->materialShader.graphicsState;
2006         } else if (type == ShaderType::DEPTH_SHADER) {
2007             entityRef = readHandle->depthShader.graphicsState;
2008         }
2009     }
2010 
2011     auto rh = rhComponentManager_->GetRenderHandleReference(entityRef);
2012     if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
2013         auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
2014         auto hash = engineShaderManager.HashGraphicsState(state);
2015         auto currentState = engineShaderManager.GetGraphicsState(rh);
2016         if (hash != engineShaderManager.HashGraphicsState(currentState)) {
2017             auto desc = engineShaderManager.GetIdDesc(rh);
2018             engineShaderManager.CreateGraphicsState({ desc.path, state });
2019         }
2020     }
2021 }
2022 
GetGraphicsState(CORE_NS::Entity materialEntity,ShaderType type,const SCENE_NS::IShaderGraphicsState::Ptr & ret)2023 bool SceneHolder::GetGraphicsState(
2024     CORE_NS::Entity materialEntity, ShaderType type, const SCENE_NS::IShaderGraphicsState::Ptr& ret)
2025 {
2026     if (!ecs_) {
2027         return false;
2028     }
2029 
2030     if (!EntityUtil::IsValid(materialEntity)) {
2031         return false;
2032     }
2033 
2034     CORE_NS::EntityReference entityRef;
2035     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
2036         if (type == ShaderType::MATERIAL_SHADER) {
2037             entityRef = readHandle->materialShader.graphicsState;
2038         } else if (type == ShaderType::DEPTH_SHADER) {
2039             entityRef = readHandle->depthShader.graphicsState;
2040         }
2041     }
2042     auto rh = rhComponentManager_->GetRenderHandleReference(entityRef);
2043     if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
2044         auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
2045         auto state = engineShaderManager.GetGraphicsState(rh);
2046         if (auto typed = interface_cast<SCENE_NS::IPendingRequestData<RENDER_NS::GraphicsState>>(ret)) {
2047             typed->Add(state);
2048             return true;
2049         }
2050     }
2051     return false;
2052 }
2053 
SetShader(CORE_NS::Entity materialEntity,ShaderType type,SCENE_NS::IShader::Ptr shader)2054 void SceneHolder::SetShader(CORE_NS::Entity materialEntity, ShaderType type, SCENE_NS::IShader::Ptr shader)
2055 {
2056     if (!ecs_) {
2057         return;
2058     }
2059 
2060     if (!EntityUtil::IsValid(materialEntity)) {
2061         return;
2062     }
2063 
2064     EntityReference shaderEntityRef {};
2065     RenderHandleReference rh {};
2066 
2067     auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
2068     if (shader) {
2069         rh = shader->GetRenderHandleReference(engineShaderManager);
2070         auto uri = META_NS::GetValue(shader->Uri());
2071 
2072         if (RenderHandleUtil::IsValid(rh.GetHandle())) {
2073             shaderEntityRef = GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, rh);
2074             // Studio used to update also uri component, maybe someone else should do this
2075             // if needed to begin with
2076             if (!uriComponentManager_->HasComponent(shaderEntityRef)) {
2077                 uriComponentManager_->Create(shaderEntityRef);
2078             }
2079             if (auto handle = uriComponentManager_->Write(shaderEntityRef)) {
2080                 handle->uri = uri;
2081             }
2082         } else {
2083             CORE_LOG_W("Failed to set shader, invalid render handle: %s", uri.c_str());
2084             return;
2085         }
2086         if (auto shref = interface_cast<ISceneHolderRef>(shader)) {
2087             shref->SetSceneHolder(me_);
2088             shref->SetIndex(type);
2089         }
2090     }
2091 
2092     // Only writing the value if it has changed.
2093     bool valueChanged = false;
2094 
2095     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
2096         if (type == ShaderType::MATERIAL_SHADER) {
2097             valueChanged = readHandle->materialShader.shader != shaderEntityRef;
2098         } else if (type == ShaderType::DEPTH_SHADER) {
2099             valueChanged = readHandle->depthShader.shader != shaderEntityRef;
2100         }
2101     }
2102 
2103     if (!valueChanged) {
2104         return;
2105     }
2106 
2107     if (auto writeHandle = materialComponentManager_->Write(materialEntity)) {
2108         if (type == ShaderType::MATERIAL_SHADER) {
2109             writeHandle->materialShader.shader = shaderEntityRef;
2110             if (!writeHandle->materialShader.graphicsState) {
2111                 // initialize the graphics state handle, so we can resolve it later
2112                 if (auto graphicsStateHandle = engineShaderManager.GetGraphicsStateHandleByShaderHandle(rh)) {
2113                     writeHandle->materialShader.graphicsState =
2114                         GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, graphicsStateHandle);
2115                 }
2116             }
2117         } else if (type == ShaderType::DEPTH_SHADER) {
2118             writeHandle->depthShader.shader = shaderEntityRef;
2119             if (!writeHandle->depthShader.graphicsState) {
2120                 if (auto graphicsStateHandle = engineShaderManager.GetGraphicsStateHandleByShaderHandle(rh)) {
2121                     writeHandle->depthShader.graphicsState =
2122                         GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, graphicsStateHandle);
2123                 }
2124             }
2125         }
2126     }
2127 
2128     ProcessEvents();
2129 }
2130 
SetGraphicsState(CORE_NS::Entity materialEntity,ShaderType type,SCENE_NS::IGraphicsState::Ptr state)2131 void SceneHolder::SetGraphicsState(CORE_NS::Entity materialEntity, ShaderType type, SCENE_NS::IGraphicsState::Ptr state)
2132 {
2133     if (!ecs_) {
2134         return;
2135     }
2136 
2137     if (!EntityUtil::IsValid(materialEntity)) {
2138         return;
2139     }
2140 
2141     EntityReference stateEntityRef {};
2142     if (state) {
2143         auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
2144         auto rh = state->GetRenderHandleReference(engineShaderManager);
2145 
2146         if (RenderHandleUtil::IsValid(rh.GetHandle())) {
2147             auto uri = META_NS::GetValue(state->Uri());
2148             auto variant = META_NS::GetValue(state->Variant());
2149 
2150             stateEntityRef = GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, rh);
2151             // Studio used to update also uri component, maybe someone else should do this
2152             // if needed to begin with
2153             if (!uriComponentManager_->HasComponent(stateEntityRef)) {
2154                 uriComponentManager_->Create(stateEntityRef);
2155             }
2156             if (auto handle = uriComponentManager_->Write(stateEntityRef)) {
2157                 handle->uri = uri.append(variant);
2158             }
2159         } else {
2160             CORE_LOG_W("Failed to set shader, invalid render handle: %s", META_NS::GetValue(state->Uri()).c_str());
2161             return;
2162         }
2163         if (auto shref = interface_cast<ISceneHolderRef>(state)) {
2164             shref->SetSceneHolder(me_);
2165             shref->SetIndex(type);
2166         }
2167     }
2168 
2169     // Only writing the value if it has changed.
2170     bool valueChanged = false;
2171 
2172     if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
2173         if (type == ShaderType::MATERIAL_SHADER) {
2174             valueChanged = readHandle->materialShader.graphicsState != stateEntityRef;
2175         } else if (type == ShaderType::DEPTH_SHADER) {
2176             valueChanged = readHandle->depthShader.graphicsState != stateEntityRef;
2177         }
2178     }
2179 
2180     if (!valueChanged) {
2181         return;
2182     }
2183 
2184     if (auto writeHandle = materialComponentManager_->Write(materialEntity)) {
2185         if (type == ShaderType::MATERIAL_SHADER) {
2186             writeHandle->materialShader.graphicsState = stateEntityRef;
2187         } else if (type == ShaderType::DEPTH_SHADER) {
2188             writeHandle->depthShader.graphicsState = stateEntityRef;
2189         }
2190     }
2191 
2192     ProcessEvents();
2193 }
2194 
GetHandleUri(RENDER_NS::RenderHandleReference renderHandleReference,UriHandleType type)2195 BASE_NS::string SceneHolder::GetHandleUri(RENDER_NS::RenderHandleReference renderHandleReference, UriHandleType type)
2196 {
2197     if (ecs_ && renderContext_) {
2198         auto& device = renderContext_->GetDevice();
2199 
2200         auto& shaderManager = device.GetShaderManager();
2201 
2202         if ((type == HANDLE_TYPE_SHADER && shaderManager.IsShader(renderHandleReference)) ||
2203             (type == HANDLE_TYPE_DO_NOT_CARE)) {
2204             auto desc = shaderManager.GetIdDesc(renderHandleReference);
2205             return desc.path;
2206         }
2207     }
2208     return BASE_NS::string();
2209 }
2210 
LoadSampler(BASE_NS::string_view uri)2211 CORE_NS::Entity SceneHolder::LoadSampler(BASE_NS::string_view uri)
2212 {
2213     CORE_NS::Entity ret;
2214     if (ecs_ && renderContext_) {
2215         const auto name = uri.substr(ENGINE_URI_PREFIX_LEN);
2216         auto linearHandle = renderContext_->GetDevice().GetGpuResourceManager().GetSamplerHandle(name);
2217 
2218         auto entity = rhComponentManager_->GetEntityWithReference(linearHandle);
2219         if (!EntityUtil::IsValid(entity)) {
2220             // No existing sampler found, prepare one
2221             auto uriManager = GetManager<CORE3D_NS::IUriComponentManager>(*ecs_);
2222             entity = ecs_->GetEntityManager().Create();
2223 
2224             uriManager->Create(entity);
2225             uriManager->Write(entity)->uri = uri;
2226 
2227             rhComponentManager_->Create(entity);
2228             rhComponentManager_->Write(entity)->reference = linearHandle;
2229 
2230             RenameEntity(entity, BASE_NS::string(name.data(), name.size()));
2231             scene_->AddEntityToSubcollection("samplers", name, entity, false);
2232         }
2233         ret = entity;
2234     }
2235 
2236     return ret;
2237 }
2238 
LoadImage(BASE_NS::string_view uri,RENDER_NS::RenderHandleReference rh)2239 CORE_NS::EntityReference SceneHolder::LoadImage(BASE_NS::string_view uri, RENDER_NS::RenderHandleReference rh)
2240 {
2241     CORE_NS::Entity ret;
2242     if (FindResource(uri, uri, ret)) {
2243         return ecs_->GetEntityManager().GetReferenceCounted(ret);
2244     }
2245 
2246     if (scene_ && assetManager_) {
2247         RENDER_NS::RenderHandleReference imageHandle;
2248         if (rh) {
2249             imageHandle = rh;
2250         } else {
2251             imageHandle = assetManager_->GetEcsSerializer().LoadImageResource(uri);
2252         }
2253         if (imageHandle) {
2254             return GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, imageHandle);
2255         }
2256     }
2257 
2258     return {};
2259 }
2260 
SetSampler(size_t index,CORE_NS::Entity targetEntity,SCENE_NS::ITextureInfo::SamplerId samplerId)2261 void SceneHolder::SetSampler(size_t index, CORE_NS::Entity targetEntity, SCENE_NS::ITextureInfo::SamplerId samplerId)
2262 {
2263     if (ecs_) {
2264         if (EntityUtil::IsValid(targetEntity)) {
2265             bool wrote = false;
2266             if (auto handle = materialComponentManager_->Write(targetEntity)) {
2267                 auto entity = LoadSampler(ResolveSamplerUri(samplerId));
2268                 if (EntityUtil::IsValid(entity)) {
2269                     // both scene and texture array will hold a reference to entity
2270                     handle->textures[index].sampler = ecs_->GetEntityManager().GetReferenceCounted(entity);
2271                     wrote = true;
2272                 }
2273             }
2274             if (wrote) {
2275                 ProcessEvents();
2276             }
2277         }
2278     }
2279 }
2280 
SetSubmeshRenderSortOrder(CORE_NS::Entity targetEntity,int64_t submeshIndex,uint8_t value)2281 void SceneHolder::SetSubmeshRenderSortOrder(CORE_NS::Entity targetEntity, int64_t submeshIndex, uint8_t value)
2282 {
2283     if (ecs_) {
2284         if (EntityUtil::IsValid(targetEntity)) {
2285             bool wrote = false;
2286             if (auto handle = meshComponentManager_->Write(targetEntity)) {
2287                 if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
2288                     handle->submeshes[submeshIndex].renderSortLayerOrder = value;
2289                     wrote = true;
2290                 }
2291             }
2292             if (wrote) {
2293                 ProcessEvents();
2294             }
2295         }
2296     }
2297 }
2298 
SetSubmeshAABBMin(CORE_NS::Entity targetEntity,int64_t submeshIndex,const BASE_NS::Math::Vec3 & vec)2299 void SceneHolder::SetSubmeshAABBMin(CORE_NS::Entity targetEntity, int64_t submeshIndex, const BASE_NS::Math::Vec3& vec)
2300 {
2301     if (ecs_) {
2302         if (EntityUtil::IsValid(targetEntity)) {
2303             bool wrote = false;
2304             if (auto handle = meshComponentManager_->Write(targetEntity)) {
2305                 if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
2306                     handle->submeshes[submeshIndex].aabbMin = vec;
2307                     handle->aabbMin = min(handle->aabbMin, vec);
2308                     wrote = true;
2309                 }
2310             }
2311             if (wrote) {
2312                 ProcessEvents();
2313             }
2314         }
2315     }
2316 }
2317 
RemoveSubmesh(CORE_NS::Entity targetEntity,int64_t submeshIndex)2318 void SceneHolder::RemoveSubmesh(CORE_NS::Entity targetEntity, int64_t submeshIndex)
2319 {
2320     if (ecs_) {
2321         if (EntityUtil::IsValid(targetEntity)) {
2322             bool wrote = false;
2323             if (auto handle = meshComponentManager_->Write(targetEntity)) {
2324                 if (submeshIndex < 0) {
2325                     handle->submeshes.clear();
2326                     handle->aabbMin = { 0.f, 0.f, 0.f };
2327                     handle->aabbMax = { 0.f, 0.f, 0.f };
2328                     wrote = true;
2329                 } else if (submeshIndex < handle->submeshes.size()) {
2330                     handle->submeshes.erase(handle->submeshes.begin() + submeshIndex);
2331                     for (const auto& submesh : handle->submeshes) {
2332                         handle->aabbMin = BASE_NS::Math::min(handle->aabbMin, submesh.aabbMin);
2333                         handle->aabbMax = BASE_NS::Math::max(handle->aabbMax, submesh.aabbMax);
2334                     }
2335                     wrote = true;
2336                 }
2337             }
2338             if (wrote) {
2339                 ProcessEvents();
2340             }
2341         }
2342     }
2343 }
2344 
SetSubmeshAABBMax(CORE_NS::Entity targetEntity,int64_t submeshIndex,const BASE_NS::Math::Vec3 & vec)2345 void SceneHolder::SetSubmeshAABBMax(CORE_NS::Entity targetEntity, int64_t submeshIndex, const BASE_NS::Math::Vec3& vec)
2346 {
2347     if (ecs_) {
2348         if (EntityUtil::IsValid(targetEntity)) {
2349             bool wrote = false;
2350             if (auto handle = meshComponentManager_->Write(targetEntity)) {
2351                 if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
2352                     handle->submeshes[submeshIndex].aabbMax = vec;
2353                     handle->aabbMax = max(handle->aabbMax, vec);
2354                     wrote = true;
2355                 }
2356             }
2357             if (wrote) {
2358                 ProcessEvents();
2359             }
2360         }
2361     }
2362 }
2363 
EnableEnvironmentComponent(CORE_NS::Entity entity)2364 void SceneHolder::EnableEnvironmentComponent(CORE_NS::Entity entity)
2365 {
2366     if (ecs_) {
2367         if (EntityUtil::IsValid(entity)) {
2368             if (!envComponentManager_->HasComponent(entity)) {
2369                 envComponentManager_->Create(entity);
2370             }
2371         }
2372     }
2373 }
2374 
EnableLayerComponent(CORE_NS::Entity entity)2375 void SceneHolder::EnableLayerComponent(CORE_NS::Entity entity)
2376 {
2377     if (ecs_) {
2378         if (EntityUtil::IsValid(entity)) {
2379             if (!layerComponentManager_->HasComponent(entity)) {
2380                 layerComponentManager_->Create(entity);
2381             }
2382         }
2383     }
2384 }
2385 
EnableLightComponent(CORE_NS::Entity entity)2386 void SceneHolder::EnableLightComponent(CORE_NS::Entity entity)
2387 {
2388     if (ecs_) {
2389         if (EntityUtil::IsValid(entity)) {
2390             if (!lightComponentManager_->HasComponent(entity)) {
2391                 lightComponentManager_->Create(entity);
2392             }
2393         }
2394     }
2395 }
2396 
2397 template<typename T>
FillData(array_view<const T> c)2398 constexpr inline CORE3D_NS::IMeshBuilder::DataBuffer FillData(array_view<const T> c) noexcept
2399 {
2400     Format format = BASE_FORMAT_UNDEFINED;
2401     if constexpr (is_same_v<T, Math::Vec2>) {
2402         format = BASE_FORMAT_R32G32_SFLOAT;
2403     } else if constexpr (is_same_v<T, Math::Vec3>) {
2404         format = BASE_FORMAT_R32G32B32_SFLOAT;
2405     } else if constexpr (is_same_v<T, Math::Vec4>) {
2406         format = BASE_FORMAT_R32G32B32A32_SFLOAT;
2407     } else if constexpr (is_same_v<T, uint16_t>) {
2408         format = BASE_FORMAT_R16_UINT;
2409     } else if constexpr (is_same_v<T, uint32_t>) {
2410         format = BASE_FORMAT_R32_UINT;
2411     }
2412     return CORE3D_NS::IMeshBuilder::DataBuffer { format, sizeof(T),
2413         { reinterpret_cast<const uint8_t*>(c.data()), c.size() * sizeof(T) } };
2414 }
2415 
2416 template<typename IndicesType>
CreateMeshFromArrays(const BASE_NS::string & name,SCENE_NS::MeshGeometryArrayPtr<IndicesType> arrays,RENDER_NS::IndexType indexType,Entity existingEntity,bool append)2417 CORE_NS::Entity SceneHolder::CreateMeshFromArrays(const BASE_NS::string& name,
2418     SCENE_NS::MeshGeometryArrayPtr<IndicesType> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
2419     bool append)
2420 {
2421     if (!ecs_) {
2422         CORE_LOG_W("%s: no ecs, cannot create mesh", __func__);
2423         return {};
2424     }
2425 
2426     if (!arrays || arrays->size() == 0) {
2427         if (EntityUtil::IsValid(existingEntity)) {
2428             RemoveSubmesh(existingEntity, -1);
2429             return existingEntity;
2430         } else {
2431             // create empty, submeshes may follow
2432             auto entity = ecs_->GetEntityManager().Create();
2433 
2434             RenameEntity(entity, name);
2435 
2436             meshComponentManager_->Create(entity);
2437             scene_->AddEntityToSubcollection("created_meshes", name, entity);
2438             return entity;
2439         }
2440     }
2441 
2442     if (EntityUtil::IsValid(existingEntity) && !append) {
2443         RemoveSubmesh(existingEntity, -1);
2444     }
2445 
2446     size_t subMeshIndex = 0;
2447     auto meshBuilder = CORE_NS::CreateInstance<CORE3D_NS::IMeshBuilder>(*renderContext_, CORE3D_NS::UID_MESH_BUILDER);
2448 
2449     RENDER_NS::IShaderManager& shaderManager = renderContext_->GetDevice().GetShaderManager();
2450     const RENDER_NS::VertexInputDeclarationView vertexInputDeclaration =
2451         shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
2452             CORE3D_NS::DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
2453 
2454     meshBuilder->Initialize(vertexInputDeclaration, 1);
2455 
2456     for (auto&& geometry : *arrays.get()) {
2457         CORE3D_NS::IMeshBuilder::Submesh submesh;
2458 
2459         submesh.indexType = indexType;
2460         submesh.vertexCount = static_cast<uint32_t>(geometry->vertices.size());
2461         submesh.indexCount = static_cast<uint32_t>(geometry->indices.size());
2462         submesh.tangents = geometry->generateTangents;
2463 
2464         meshBuilder->AddSubmesh(submesh);
2465     }
2466     meshBuilder->Allocate();
2467 
2468     for (auto&& geometry : *arrays.get()) {
2469         meshBuilder->SetVertexData(subMeshIndex, FillData<BASE_NS::Math::Vec3>(geometry->vertices),
2470             FillData<BASE_NS::Math::Vec3>(geometry->normals), FillData<BASE_NS::Math::Vec2>(geometry->uvs),
2471             FillData<BASE_NS::Math::Vec2>(geometry->uv2s), FillData<BASE_NS::Math::Vec4>(geometry->tangents),
2472             FillData<BASE_NS::Math::Vec4>(geometry->colors));
2473         meshBuilder->CalculateAABB(subMeshIndex, FillData<BASE_NS::Math::Vec3>(geometry->vertices));
2474         meshBuilder->SetIndexData(subMeshIndex, FillData<IndicesType>(geometry->indices));
2475     }
2476 
2477     auto entity = meshBuilder->CreateMesh(*ecs_);
2478 
2479     if (EntityUtil::IsValid(existingEntity)) {
2480         for (size_t ii = 0; ii < arrays->size(); ii++) {
2481             CopySubMesh(existingEntity, entity, ii);
2482         }
2483         ecs_->GetEntityManager().Destroy(entity);
2484         return existingEntity;
2485     }
2486 
2487     RenameEntity(entity, name);
2488     scene_->AddEntityToSubcollection("created_meshes", name, entity);
2489 
2490     ProcessEvents();
2491     return entity;
2492 }
2493 
2494 // we rely that someone else will ret up correct flags to components
SetMultiviewCamera(CORE_NS::Entity target,CORE_NS::Entity source)2495 void SceneHolder::SetMultiviewCamera(CORE_NS::Entity target, CORE_NS::Entity source)
2496 {
2497     if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
2498         !cameraComponentManager_->HasComponent(source) || !cameraComponentManager_->HasComponent(target)) {
2499         CORE_LOG_W("%s: camera component not valid", __func__);
2500         return;
2501     }
2502     if (auto handle = cameraComponentManager_->Write(target)) {
2503         for (auto& ref : handle->multiViewCameras) {
2504             if (ref.id == target.id) {
2505                 return;
2506             }
2507         }
2508         handle->multiViewCameras.push_back(source);
2509     }
2510 }
2511 
2512 // we rely that someone else will ret up correct flags to components
RemoveMultiviewCamera(CORE_NS::Entity target,CORE_NS::Entity source)2513 void SceneHolder::RemoveMultiviewCamera(CORE_NS::Entity target, CORE_NS::Entity source)
2514 {
2515     if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
2516         !cameraComponentManager_->HasComponent(source) || !cameraComponentManager_->HasComponent(target)) {
2517         CORE_LOG_W("%s: camera component not valid", __func__);
2518         return;
2519     }
2520     if (auto handle = cameraComponentManager_->Write(target)) {
2521         for (size_t ii = 0; ii < handle->multiViewCameras.size(); ii++) {
2522             if (handle->multiViewCameras[ii] == target) {
2523                 handle->multiViewCameras.erase(handle->multiViewCameras.cbegin() + ii);
2524                 return;
2525             }
2526         }
2527     }
2528 }
2529 
CopySubMesh(CORE_NS::Entity target,CORE_NS::Entity source,size_t index)2530 void SceneHolder::CopySubMesh(CORE_NS::Entity target, CORE_NS::Entity source, size_t index)
2531 {
2532     if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
2533         !meshComponentManager_->HasComponent(source)) {
2534         CORE_LOG_W("%s: cannot copy submesh", __func__);
2535         return;
2536     }
2537 
2538     bool wrote = false;
2539     if (auto sourceComponent = meshComponentManager_->Read(source)) {
2540         if (sourceComponent->submeshes.size() > index) {
2541             if (!meshComponentManager_->HasComponent(target)) {
2542                 meshComponentManager_->Create(target);
2543             }
2544             if (auto targetComponent = meshComponentManager_->Write(target)) {
2545                 targetComponent->submeshes.push_back(CORE3D_NS::MeshComponent::Submesh());
2546                 // Todo: verify if copy by assignment is enough, or do we need deep copy
2547                 // and explicit reference modifications
2548                 targetComponent->submeshes.back() = sourceComponent->submeshes.at(index);
2549                 for (const auto& submesh : targetComponent->submeshes) {
2550                     targetComponent->aabbMin = BASE_NS::Math::min(targetComponent->aabbMin, submesh.aabbMin);
2551                     targetComponent->aabbMax = BASE_NS::Math::max(targetComponent->aabbMax, submesh.aabbMax);
2552                 }
2553                 wrote = true;
2554             }
2555         }
2556     }
2557     if (wrote) {
2558         ProcessEvents();
2559     }
2560 }
2561 
ReleaseOwnership(CORE_NS::Entity entity)2562 void SceneHolder::ReleaseOwnership(CORE_NS::Entity entity)
2563 {
2564     if (ecs_ && scene_) {
2565         if (EntityUtil::IsValid(entity)) {
2566             if (const auto cachedEntity = FindCachedRelatedEntity(entity);
2567                 EntityUtil::IsValid(cachedEntity) && entity != cachedEntity) {
2568                 SCENE_PLUGIN_VERBOSE_LOG("%s: Cached entity does not match: entity: %I64u, cachedEntity: %I64u",
2569                     __func__, entity.id, cachedEntity.id);
2570                 if (auto cachedIdx = scene_->GetSubCollectionIndexByRoot(cachedEntity); cachedIdx != -1) {
2571                     scene_->GetSubCollection(cachedIdx)->SetActive(false);
2572                     scene_->RemoveEntityRecursive(cachedEntity);
2573                 }
2574             }
2575             scene_->RemoveEntityRecursive(entity);
2576         }
2577     }
2578 }
2579 
2580 // Reposition a node within its parent
ReindexEntity(CORE_NS::Entity target,size_t index)2581 void SceneHolder::ReindexEntity(CORE_NS::Entity target, size_t index)
2582 {
2583     if (ecs_ && scene_ && EntityUtil::IsValid(target)) {
2584         // Get the node
2585         if (auto node = nodeSystem_->GetNode(target)) {
2586             // Get the parent
2587             if (auto parent = node->GetParent()) {
2588                 parent->RemoveChild(*node);
2589                 parent->InsertChild(index, *node);
2590             }
2591         }
2592 
2593         // do we need to adjust also collection manually (it should be reference only)
2594         scene_->MarkModified(true, true);
2595     }
2596 }
2597 
2598 template CORE_NS::Entity SceneHolder::CreateMeshFromArrays<uint16_t>(const BASE_NS::string& name,
2599     SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
2600     bool append);
2601 
2602 template CORE_NS::Entity SceneHolder::CreateMeshFromArrays<uint32_t>(const BASE_NS::string& name,
2603     SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
2604     bool append);
2605 
GetUniqueName()2606 string SceneHolder::GetUniqueName()
2607 {
2608     return instanceId_.ToString().append(to_string(++instanceNumber_));
2609 }
2610 
2611 // Enable new multi-mesh batch
CreateMultiMeshInstance(CORE_NS::Entity baseComponent)2612 CORE_NS::Entity SceneHolder::CreateMultiMeshInstance(CORE_NS::Entity baseComponent)
2613 {
2614     if (ecs_) {
2615         if (!nodeSystem_->GetNode(baseComponent)) {
2616             CORE_LOG_I("%s: selected base entity does not have node on ecs", __func__);
2617 
2618             // Now, the assumption is that entity should have either RenderMeshComponent or MeshComponent
2619             // It is bit open if it has render mesh component, shoud we copy its mesh data implicitly
2620             CORE3D_NS::RenderMeshComponent renderMeshData;
2621 
2622             if (auto data = renderMeshComponentManager_->Read(baseComponent)) {
2623                 renderMeshData = *data;
2624             }
2625 
2626             auto node = nodeSystem_->CreateNode();
2627             auto nodeEntity = node->GetEntity();
2628 
2629             renderMeshComponentManager_->Create(nodeEntity);
2630             if (auto data = renderMeshComponentManager_->Write(nodeEntity)) {
2631                 *data = renderMeshData;
2632 
2633                 if (!EntityUtil::IsValid(data->mesh)) {
2634                     // base component may have mesh component, or then it does not
2635                     data->mesh = baseComponent;
2636                 }
2637             }
2638             baseComponent = nodeEntity;
2639         }
2640 
2641         if (!renderMeshComponentManager_->HasComponent(baseComponent)) {
2642             renderMeshComponentManager_->Create(baseComponent);
2643         }
2644     }
2645 
2646     return baseComponent;
2647 }
2648 
2649 static constexpr size_t MULTI_MESH_CHILD_PREFIX_LEN = MULTI_MESH_CHILD_PREFIX.size();
2650 
IsMultiMeshChild(const CORE3D_NS::ISceneNode * child)2651 bool SceneHolder::IsMultiMeshChild(const CORE3D_NS::ISceneNode* child)
2652 {
2653     auto entity = child->GetEntity();
2654     if (auto nameHandle = nameComponentManager_->Read(entity)) {
2655         auto name = BASE_NS::string_view(nameHandle->name.data(), nameHandle->name.size());
2656         if (name.compare(0, MULTI_MESH_CHILD_PREFIX_LEN, MULTI_MESH_CHILD_PREFIX) == 0) {
2657             return true;
2658         }
2659     }
2660     return false;
2661 }
2662 
FindCachedRelatedEntity(const CORE_NS::Entity & entity)2663 CORE_NS::Entity SceneHolder::FindCachedRelatedEntity(const CORE_NS::Entity& entity)
2664 {
2665     if (!(scene_ && nodeSystem_ && CORE_NS::EntityUtil::IsValid(entity))) {
2666         return {};
2667     }
2668 
2669     CORE_NS::Entity cachedEntity {};
2670     if (const auto node = nodeSystem_->GetNode(entity)) {
2671         if (const auto idx = scene_->GetSubCollectionIndex(node->GetName()); idx != -1) {
2672             cachedEntity = scene_->GetSubCollection(idx)->GetEntity("/");
2673         }
2674     }
2675 
2676     return cachedEntity;
2677 }
2678 
2679 // Set mesh to multi-mesh
SetMeshMultimeshArray(CORE_NS::Entity target,CORE_NS::Entity mesh)2680 void SceneHolder::SetMeshMultimeshArray(CORE_NS::Entity target, CORE_NS::Entity mesh)
2681 {
2682     if (ecs_) {
2683         if (auto data = renderMeshComponentManager_->Write(target)) {
2684             data->mesh = mesh;
2685         }
2686 
2687         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2688             MeshComponent givenData;
2689             if (auto givenMeshData = meshComponentManager_->Read(mesh)) {
2690                 givenData = *givenMeshData;
2691             }
2692 
2693             for (auto& child : parent->GetChildren()) {
2694                 auto entity = child->GetEntity();
2695                 if (!IsMultiMeshChild(child)) {
2696                     continue;
2697                 }
2698 
2699                 if (auto data = renderMeshComponentManager_->Read(entity)) {
2700                     auto mesh = data->mesh;
2701                     if (auto meshData = meshComponentManager_->Write(mesh)) {
2702                         *meshData = givenData;
2703                     }
2704                 }
2705 
2706                 if (auto data = renderMeshComponentManager_->Write(entity)) {
2707                     data->renderMeshBatch = target;
2708                 }
2709             }
2710         }
2711     }
2712 }
2713 
SetAll(CORE_NS::Entity target,CORE_NS::Entity material,BASE_NS::vector<CORE_NS::Entity> & ret,CORE3D_NS::IMeshComponentManager * meshComponentManager)2714 void SetAll(CORE_NS::Entity target, CORE_NS::Entity material, BASE_NS::vector<CORE_NS::Entity>& ret,
2715     CORE3D_NS::IMeshComponentManager* meshComponentManager)
2716 {
2717     if (EntityUtil::IsValid(target)) {
2718         if (auto handle = meshComponentManager->Write(target)) {
2719             for (auto&& submesh : handle->submeshes) {
2720                 ret.push_back(submesh.material);
2721                 submesh.material = material;
2722             }
2723         }
2724     }
2725 }
2726 
ResetAll(CORE_NS::Entity target,BASE_NS::vector<CORE_NS::Entity> & in,CORE3D_NS::IMeshComponentManager * meshComponentManager)2727 void ResetAll(CORE_NS::Entity target, BASE_NS::vector<CORE_NS::Entity>& in,
2728     CORE3D_NS::IMeshComponentManager* meshComponentManager)
2729 {
2730     if (EntityUtil::IsValid(target)) {
2731         if (auto handle = meshComponentManager->Write(target)) {
2732             for (auto&& submesh : handle->submeshes) {
2733                 if (in.size() > 0) {
2734                     submesh.material = in.front();
2735                     in.erase(in.begin());
2736                 }
2737             }
2738         }
2739     }
2740 }
2741 
2742 // Set override material to multi-mesh
SetOverrideMaterialMultimeshArray(CORE_NS::Entity target,CORE_NS::Entity material)2743 BASE_NS::vector<CORE_NS::Entity> SceneHolder::SetOverrideMaterialMultimeshArray(
2744     CORE_NS::Entity target, CORE_NS::Entity material)
2745 {
2746     BASE_NS::vector<CORE_NS::Entity> ret;
2747     if (ecs_) {
2748         // if we contain render mesh handle, use it to set material
2749         if (auto data = renderMeshComponentManager_->Read(target)) {
2750             auto mesh = data->mesh;
2751             SetAll(mesh, material, ret, meshComponentManager_);
2752         }
2753 
2754         // if our child contain meshes, update material on those
2755         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2756             for (auto& child : parent->GetChildren()) {
2757                 if (IsMultiMeshChild(child)) {
2758                     auto entity = child->GetEntity();
2759                     if (auto data = renderMeshComponentManager_->Read(entity)) {
2760                         auto mesh = data->mesh;
2761                         SetAll(mesh, material, ret, meshComponentManager_);
2762                     }
2763                 }
2764             }
2765         }
2766     }
2767     return ret;
2768 }
2769 
2770 // reset override material from multi-mesh
ResetOverrideMaterialMultimeshArray(CORE_NS::Entity target,BASE_NS::vector<CORE_NS::Entity> & in)2771 void SceneHolder::ResetOverrideMaterialMultimeshArray(CORE_NS::Entity target, BASE_NS::vector<CORE_NS::Entity>& in)
2772 {
2773     if (ecs_) {
2774         BASE_NS::vector<CORE_NS::Entity> ret;
2775 
2776         // if we contain render mesh handle, use it to set material
2777         if (auto data = renderMeshComponentManager_->Read(target)) {
2778             auto mesh = data->mesh;
2779             ResetAll(mesh, in, meshComponentManager_);
2780         }
2781 
2782         // if our child contain meshes, update material on those
2783         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2784             for (auto& child : parent->GetChildren()) {
2785                 if (IsMultiMeshChild(child)) {
2786                     auto entity = child->GetEntity();
2787                     if (auto data = renderMeshComponentManager_->Read(entity)) {
2788                         auto mesh = data->mesh;
2789                         ResetAll(mesh, in, meshComponentManager_);
2790                     }
2791                 }
2792             }
2793         }
2794     }
2795     in.clear();
2796 }
2797 
2798 // Set instance count to multi-mesh
SetInstanceCountMultimeshArray(CORE_NS::Entity target,size_t count)2799 void SceneHolder::SetInstanceCountMultimeshArray(CORE_NS::Entity target, size_t count)
2800 {
2801     if (ecs_) {
2802         if (auto parent = nodeSystem_->GetNode(target)) {
2803             // this is kind of sub-optimization. If we have instances available, the mesh component is stored only
2804             // in instances
2805             CORE_NS::Entity firstBorn;
2806             auto children = parent->GetChildren();
2807 
2808             for (auto& child : children) {
2809                 if (IsMultiMeshChild(child)) {
2810                     firstBorn = child->GetEntity();
2811                     break;
2812                 }
2813             }
2814 
2815             CORE3D_NS::MeshComponent meshData;
2816 
2817             // when the instance count goes back to zero, we need to restore the data on parent
2818             if (count == 0) {
2819                 if (CORE_NS::EntityUtil::IsValid(firstBorn)) {
2820                     renderMeshComponentManager_->Create(target);
2821                     if (auto renderMeshData = renderMeshComponentManager_->Write(target)) {
2822                         if (auto instancingData = renderMeshComponentManager_->Read(firstBorn)) {
2823                             *renderMeshData = *instancingData;
2824                         }
2825                     }
2826                 }
2827                 // now, when we move the templated item back to root, it will become visible by default
2828             } else {
2829                 // if we have mesh, set things up using mesh
2830                 if (auto data = meshComponentManager_->Read(target)) {
2831                     meshData = *data;
2832                 } else if (auto instanceData = renderMeshComponentManager_->Read(firstBorn)) {
2833                     // otherwise we prefer the instanced data
2834                     if (auto data = meshComponentManager_->Read(instanceData->mesh)) {
2835                         // use instance data
2836                         meshData = *data;
2837                         // and switch target
2838                         target = firstBorn;
2839                     }
2840                 } else if (auto renderMeshData = renderMeshComponentManager_->Read(target)) {
2841                     // and fallback to existing render mesh data if it exists
2842                     if (auto data = meshComponentManager_->Read(renderMeshData->mesh)) {
2843                         meshData = *data;
2844                     }
2845                 }
2846             }
2847 
2848             size_t mmcount = 0;
2849             for (auto& child : children) {
2850                 if (IsMultiMeshChild(child)) {
2851                     if (mmcount == count) {
2852                         parent->RemoveChild(*child);
2853                     } else {
2854                         mmcount++;
2855                     }
2856                 }
2857             }
2858 
2859             BASE_NS::vector<CORE_NS::Entity> clones;
2860             while (mmcount < count) {
2861                 clones.push_back(ecs_->CloneEntity(target));
2862                 mmcount++;
2863             }
2864 
2865             for (auto clone : clones) {
2866                 // set up node system
2867                 auto node = nodeSystem_->GetNode(clone);
2868                 node->SetParent(*parent);
2869                 node->SetEnabled(true);
2870                 nameComponentManager_->Create(clone);
2871 
2872                 // set up name so we can identify cloned instances afterwards
2873                 if (auto nameHandle = nameComponentManager_->Write(clone)) {
2874                     BASE_NS::string postFixed(MULTI_MESH_CHILD_PREFIX.data(), MULTI_MESH_CHILD_PREFIX.size());
2875                     postFixed.append(BASE_NS::to_string(mmcount));
2876                     nameHandle->name = postFixed;
2877                 }
2878 
2879                 // and finally mesh specifics
2880                 if (auto rmcHandle = renderMeshComponentManager_->Write(clone)) {
2881                     // during the first clone, switch from template to first instance
2882                     if (mmcount == 0) {
2883                         renderMeshComponentManager_->Destroy(target);
2884                         target = clone;
2885                     }
2886                     // Set batch
2887                     rmcHandle->renderMeshBatch = target;
2888                     // create new entity for mesh
2889                     const CORE_NS::Entity entity = ecs_->GetEntityManager().Create();
2890                     meshComponentManager_->Create(entity);
2891                     // copy the data of the original
2892                     *meshComponentManager_->Write(entity) = meshData;
2893                     // and set the mesh to a new instance
2894                     rmcHandle->mesh = entity;
2895                 }
2896                 mmcount++;
2897             }
2898             // Set up a batch
2899             auto renderMeshBatchComponentManager =
2900                 CORE_NS::GetManager<CORE3D_NS::IRenderMeshBatchComponentManager>(*ecs_);
2901             if (!renderMeshBatchComponentManager->HasComponent(firstBorn)) {
2902                 renderMeshBatchComponentManager->Create(firstBorn);
2903             }
2904             if (auto batchHandle = renderMeshBatchComponentManager->Write(firstBorn)) {
2905                 batchHandle->batchType = CORE3D_NS::RenderMeshBatchComponent::BatchType::GPU_INSTANCING;
2906             }
2907         }
2908     }
2909 }
2910 
2911 // Set visible count to multi-mesh
SetVisibleCountMultimeshArray(CORE_NS::Entity target,size_t count)2912 void SceneHolder::SetVisibleCountMultimeshArray(CORE_NS::Entity target, size_t count)
2913 {
2914     if (ecs_) {
2915         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2916             size_t ix = 0;
2917             for (auto& child : parent->GetChildren()) {
2918                 if (IsMultiMeshChild(child)) {
2919                     child->SetEnabled(ix < count);
2920                     ix++;
2921                 }
2922             }
2923         }
2924     }
2925 }
2926 
2927 // Set custom data to multi-mesh index
SetCustomData(CORE_NS::Entity target,size_t index,const BASE_NS::Math::Vec4 & data)2928 void SceneHolder::SetCustomData(CORE_NS::Entity target, size_t index, const BASE_NS::Math::Vec4& data)
2929 {
2930     if (ecs_) {
2931         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2932             size_t ix = 0;
2933             for (auto& child : parent->GetChildren()) {
2934                 if (IsMultiMeshChild(child)) {
2935                     if (ix == index) {
2936                         auto entity = child->GetEntity();
2937                         if (auto handle = renderMeshComponentManager_->Write(entity)) {
2938                             *static_cast<float*>(static_cast<void*>(&handle->customData[0].x)) = data.x;
2939                             *static_cast<float*>(static_cast<void*>(&handle->customData[0].y)) = data.y;
2940                             *static_cast<float*>(static_cast<void*>(&handle->customData[0].z)) = data.z;
2941                             *static_cast<float*>(static_cast<void*>(&handle->customData[0].w)) = data.w;
2942                         }
2943                         return;
2944                     }
2945                     ix++;
2946                 }
2947             }
2948         }
2949     }
2950 }
2951 
2952 // Set transformation to multi-mesh index
SetTransformation(CORE_NS::Entity target,size_t index,const BASE_NS::Math::Mat4X4 & transform)2953 void SceneHolder::SetTransformation(CORE_NS::Entity target, size_t index, const BASE_NS::Math::Mat4X4& transform)
2954 {
2955     if (ecs_) {
2956         if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
2957             size_t ix = 0;
2958             for (auto& child : parent->GetChildren()) {
2959                 if (IsMultiMeshChild(child)) {
2960                     if (ix == index) {
2961                         auto entity = child->GetEntity();
2962                         if (auto handle = transformComponentManager_->Write(entity)) {
2963                             BASE_NS::Math::Quat rotation;
2964                             BASE_NS::Math::Vec3 scale;
2965                             BASE_NS::Math::Vec3 position;
2966                             BASE_NS::Math::Vec3 skew;
2967                             BASE_NS::Math::Vec4 persp;
2968                             if (BASE_NS::Math::Decompose(transform, scale, rotation, position, skew, persp)) {
2969                                 handle->scale = scale;
2970                                 handle->rotation = rotation;
2971                                 handle->position = position;
2972                             }
2973                             return;
2974                         }
2975                     }
2976                     ix++;
2977                 }
2978             }
2979         }
2980     }
2981 }
2982 
GetWorldMatrixComponentAABB(SCENE_NS::IPickingResult::Ptr ret,CORE_NS::Entity entity,bool isRecursive)2983 bool SceneHolder::GetWorldMatrixComponentAABB(
2984     SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity entity, bool isRecursive)
2985 {
2986     if (picking_ && ecs_) {
2987         auto result = picking_->GetWorldMatrixComponentAABB(entity, isRecursive, *ecs_);
2988         if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
2989             writable->Add(result.minAABB);
2990             writable->Add(result.maxAABB);
2991             return true;
2992         }
2993     }
2994     return false;
2995 }
2996 
GetTransformComponentAABB(SCENE_NS::IPickingResult::Ptr ret,CORE_NS::Entity entity,bool isRecursive)2997 bool SceneHolder::GetTransformComponentAABB(SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity entity, bool isRecursive)
2998 {
2999     if (picking_ && ecs_) {
3000         auto result = picking_->GetTransformComponentAABB(entity, isRecursive, *ecs_);
3001         if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3002             writable->Add(result.minAABB);
3003             writable->Add(result.maxAABB);
3004             return true;
3005         }
3006     }
3007     return false;
3008 }
3009 
GetWorldAABB(SCENE_NS::IPickingResult::Ptr ret,const BASE_NS::Math::Mat4X4 & world,const BASE_NS::Math::Vec3 & aabbMin,const BASE_NS::Math::Vec3 & aabbMax)3010 bool SceneHolder::GetWorldAABB(SCENE_NS::IPickingResult::Ptr ret, const BASE_NS::Math::Mat4X4& world,
3011     const BASE_NS::Math::Vec3& aabbMin, const BASE_NS::Math::Vec3& aabbMax)
3012 {
3013     if (picking_ && ecs_) {
3014         auto result = picking_->GetWorldAABB(world, aabbMin, aabbMax);
3015         if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3016             writable->Add(result.minAABB);
3017             writable->Add(result.maxAABB);
3018             return true;
3019         }
3020     }
3021     return false;
3022 }
3023 
ConvertToToolkit(const BASE_NS::vector<CORE3D_NS::RayCastResult> & result,SCENE_NS::IRayCastResult::Ptr ret)3024 bool ConvertToToolkit(const BASE_NS::vector<CORE3D_NS::RayCastResult>& result, SCENE_NS::IRayCastResult::Ptr ret)
3025 {
3026     if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>(ret)) {
3027         for (auto& value : result) {
3028             BASE_NS::string path;
3029             if (ResolveNodeFullPath(value.node, path)) {
3030                 writable->Add({ {}, value.distance });
3031                 writable->MetaData().push_back(path);
3032             }
3033         }
3034         return true;
3035     }
3036     return false;
3037 }
3038 
RayCast(SCENE_NS::IRayCastResult::Ptr ret,const BASE_NS::Math::Vec3 & start,const BASE_NS::Math::Vec3 & direction)3039 bool SceneHolder::RayCast(
3040     SCENE_NS::IRayCastResult::Ptr ret, const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction)
3041 {
3042     if (picking_ && ecs_) {
3043         auto result = picking_->RayCast(*ecs_, start, direction);
3044         return ConvertToToolkit(result, ret);
3045     }
3046     return false;
3047 }
3048 
RayCast(SCENE_NS::IRayCastResult::Ptr ret,const BASE_NS::Math::Vec3 & start,const BASE_NS::Math::Vec3 & direction,uint64_t layerMask)3049 bool SceneHolder::RayCast(SCENE_NS::IRayCastResult::Ptr ret, const BASE_NS::Math::Vec3& start,
3050     const BASE_NS::Math::Vec3& direction, uint64_t layerMask)
3051 {
3052     if (picking_ && ecs_) {
3053         auto result = picking_->RayCast(*ecs_, start, direction, layerMask);
3054         return ConvertToToolkit(result, ret);
3055     }
3056     return false;
3057 }
3058 
ScreenToWorld(SCENE_NS::IPickingResult::Ptr ret,CORE_NS::Entity camera,BASE_NS::Math::Vec3 screenCoordinate)3059 bool SceneHolder::ScreenToWorld(
3060     SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec3 screenCoordinate)
3061 {
3062     if (picking_ && ecs_) {
3063         auto result = picking_->ScreenToWorld(*ecs_, camera, screenCoordinate);
3064         if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3065             writable->Add(result);
3066             return true;
3067         }
3068     }
3069     return false;
3070 }
3071 
WorldToScreen(SCENE_NS::IPickingResult::Ptr ret,CORE_NS::Entity camera,BASE_NS::Math::Vec3 worldCoordinate)3072 bool SceneHolder::WorldToScreen(
3073     SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec3 worldCoordinate)
3074 
3075 {
3076     if (picking_ && ecs_) {
3077         auto result = picking_->WorldToScreen(*ecs_, camera, worldCoordinate);
3078         if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3079             writable->Add(result);
3080             return true;
3081         }
3082     }
3083     return false;
3084 }
3085 
RayCastFromCamera(SCENE_NS::IRayCastResult::Ptr ret,CORE_NS::Entity camera,const BASE_NS::Math::Vec2 & screenPos)3086 bool SceneHolder::RayCastFromCamera(
3087     SCENE_NS::IRayCastResult::Ptr ret, CORE_NS::Entity camera, const BASE_NS::Math::Vec2& screenPos)
3088 {
3089     if (picking_ && ecs_) {
3090         auto result = picking_->RayCastFromCamera(*ecs_, camera, screenPos);
3091         return ConvertToToolkit(result, ret);
3092     }
3093     return false;
3094 }
3095 
RayCastFromCamera(SCENE_NS::IRayCastResult::Ptr ret,CORE_NS::Entity camera,const BASE_NS::Math::Vec2 & screenPos,uint64_t layerMask)3096 bool SceneHolder::RayCastFromCamera(
3097     SCENE_NS::IRayCastResult::Ptr ret, CORE_NS::Entity camera, const BASE_NS::Math::Vec2& screenPos, uint64_t layerMask)
3098 {
3099     if (picking_ && ecs_) {
3100         auto result = picking_->RayCastFromCamera(*ecs_, camera, screenPos, layerMask);
3101         return ConvertToToolkit(result, ret);
3102     }
3103     return false;
3104 }
3105 
RayFromCamera(SCENE_NS::IPickingResult::Ptr ret,CORE_NS::Entity camera,BASE_NS::Math::Vec2 screenCoordinate)3106 bool SceneHolder::RayFromCamera(
3107     SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec2 screenCoordinate)
3108 {
3109     if (auto cameraComponent = cameraComponentManager_->Read(camera)) {
3110         if (auto worldMatrixManager = GetManager<CORE3D_NS::IWorldMatrixComponentManager>(*ecs_)) {
3111             if (auto cameraWorldMatrixComponent = worldMatrixManager->Read(camera)) {
3112                 if (cameraComponent->projection == CORE3D_NS::CameraComponent::Projection::ORTHOGRAPHIC) {
3113                     const auto worldPos = picking_->ScreenToWorld(
3114                         *ecs_, camera, BASE_NS::Math::Vec3(screenCoordinate.x, screenCoordinate.y, 0.0f));
3115                     const auto direction =
3116                         cameraWorldMatrixComponent->matrix * BASE_NS::Math::Vec4(0.0f, 0.0f, -1.0f, 0.0f);
3117                     if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3118                         writable->Add(worldPos);
3119                         writable->Add(direction);
3120                         return true;
3121                     }
3122                 } else {
3123                     // Ray origin is the camera world position.
3124                     const auto rayOrigin = BASE_NS::Math::Vec3(cameraWorldMatrixComponent->matrix.w);
3125                     const auto targetPos = picking_->ScreenToWorld(
3126                         *ecs_, camera, BASE_NS::Math::Vec3(screenCoordinate.x, screenCoordinate.y, 1.0f));
3127                     const auto direction = BASE_NS::Math::Normalize(targetPos - rayOrigin);
3128                     if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
3129                         writable->Add(rayOrigin);
3130                         writable->Add(direction);
3131                         return true;
3132                     }
3133                 }
3134             }
3135         }
3136     }
3137     return false;
3138 }
3139