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