18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "scene_holder.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci#include <chrono>
208bf80f4bSopenharmony_ci#include <inttypes.h>
218bf80f4bSopenharmony_ci#include <scene_plugin/api/material.h>
228bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_scene.h>
238bf80f4bSopenharmony_ci
248bf80f4bSopenharmony_ci#include <3d/ecs/components/environment_component.h>
258bf80f4bSopenharmony_ci#include <3d/ecs/components/local_matrix_component.h>
268bf80f4bSopenharmony_ci#include <3d/ecs/components/post_process_component.h>
278bf80f4bSopenharmony_ci#include <3d/ecs/components/render_configuration_component.h>
288bf80f4bSopenharmony_ci#include <3d/ecs/components/render_handle_component.h>
298bf80f4bSopenharmony_ci#include <3d/ecs/components/render_mesh_batch_component.h>
308bf80f4bSopenharmony_ci#include <3d/ecs/components/transform_component.h>
318bf80f4bSopenharmony_ci#include <3d/ecs/components/uri_component.h>
328bf80f4bSopenharmony_ci#include <3d/ecs/components/world_matrix_component.h>
338bf80f4bSopenharmony_ci#include <3d/ecs/systems/intf_render_preprocessor_system.h>
348bf80f4bSopenharmony_ci#include <3d/implementation_uids.h>
358bf80f4bSopenharmony_ci#include <3d/render/default_material_constants.h>
368bf80f4bSopenharmony_ci#include <3d/util/intf_mesh_builder.h>
378bf80f4bSopenharmony_ci#include <3d/util/intf_scene_util.h>
388bf80f4bSopenharmony_ci#include <base/util/uid_util.h>
398bf80f4bSopenharmony_ci#include <core/ecs/intf_system_graph_loader.h>
408bf80f4bSopenharmony_ci#include <core/intf_engine.h>
418bf80f4bSopenharmony_ci#include <core/plugin/intf_class_factory.h>
428bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h>
438bf80f4bSopenharmony_ci#include <render/device/intf_shader_manager.h>
448bf80f4bSopenharmony_ci#include <render/intf_render_context.h>
458bf80f4bSopenharmony_ci#include <render/intf_renderer.h>
468bf80f4bSopenharmony_ci#include <render/util/intf_render_util.h>
478bf80f4bSopenharmony_ci
488bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
498bf80f4bSopenharmony_ci#include <meta/base/shared_ptr.h>
508bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue.h>
518bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h>
528bf80f4bSopenharmony_ci
538bf80f4bSopenharmony_ci#include "asset_loader.h"
548bf80f4bSopenharmony_ci#include "asset_manager.h"
558bf80f4bSopenharmony_ci#include "ecs_util.h"
568bf80f4bSopenharmony_ci#include "entity_collection.h"
578bf80f4bSopenharmony_ci#include "intf_node_private.h"
588bf80f4bSopenharmony_ci#include "task_utils.h"
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_ci// Initialize ecs on scene holder initialization or do it lazily when there's a scene to load
618bf80f4bSopenharmony_ci
628bf80f4bSopenharmony_ciusing namespace BASE_NS;
638bf80f4bSopenharmony_ciusing namespace CORE_NS;
648bf80f4bSopenharmony_ciusing namespace CORE3D_NS;
658bf80f4bSopenharmony_ciusing namespace RENDER_NS;
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask;
688bf80f4bSopenharmony_ci
698bf80f4bSopenharmony_cinamespace {
708bf80f4bSopenharmony_ci
718bf80f4bSopenharmony_cibool TickFrame(IEcs& ecs, uint64_t totalTime, uint64_t deltaTime)
728bf80f4bSopenharmony_ci{
738bf80f4bSopenharmony_ci    // run garbage collection before updating the systems to ensure only valid entities/ components are available.
748bf80f4bSopenharmony_ci    ecs.ProcessEvents();
758bf80f4bSopenharmony_ci
768bf80f4bSopenharmony_ci    const bool needRender = ecs.Update(totalTime, deltaTime);
778bf80f4bSopenharmony_ci
788bf80f4bSopenharmony_ci    // do gc also after the systems have been updated to ensure any deletes done by systems are effective
798bf80f4bSopenharmony_ci    // and client doesn't see stale entities.
808bf80f4bSopenharmony_ci    ecs.ProcessEvents();
818bf80f4bSopenharmony_ci
828bf80f4bSopenharmony_ci    return needRender;
838bf80f4bSopenharmony_ci}
848bf80f4bSopenharmony_ciconstexpr GpuImageDesc GetColorImageDesc(const uint32_t width, const uint32_t height)
858bf80f4bSopenharmony_ci{
868bf80f4bSopenharmony_ci    GpuImageDesc resolveDesc;
878bf80f4bSopenharmony_ci    resolveDesc.width = width;
888bf80f4bSopenharmony_ci    resolveDesc.height = height;
898bf80f4bSopenharmony_ci    resolveDesc.depth = 1;
908bf80f4bSopenharmony_ci    resolveDesc.format = BASE_NS::Format::BASE_FORMAT_R8G8B8A8_SRGB;
918bf80f4bSopenharmony_ci    resolveDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
928bf80f4bSopenharmony_ci    resolveDesc.usageFlags =
938bf80f4bSopenharmony_ci        ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT;
948bf80f4bSopenharmony_ci    resolveDesc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
958bf80f4bSopenharmony_ci    resolveDesc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
968bf80f4bSopenharmony_ci    resolveDesc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
978bf80f4bSopenharmony_ci    resolveDesc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
988bf80f4bSopenharmony_ci    return resolveDesc;
998bf80f4bSopenharmony_ci}
1008bf80f4bSopenharmony_ci
1018bf80f4bSopenharmony_ciconstexpr GpuImageDesc GetDepthImageDesc(const uint32_t width, const uint32_t height)
1028bf80f4bSopenharmony_ci{
1038bf80f4bSopenharmony_ci    GpuImageDesc resolveDesc;
1048bf80f4bSopenharmony_ci    resolveDesc.width = width;
1058bf80f4bSopenharmony_ci    resolveDesc.height = height;
1068bf80f4bSopenharmony_ci    resolveDesc.depth = 1;
1078bf80f4bSopenharmony_ci    resolveDesc.format = BASE_NS::Format::BASE_FORMAT_D16_UNORM;
1088bf80f4bSopenharmony_ci    resolveDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1098bf80f4bSopenharmony_ci    resolveDesc.usageFlags = ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
1108bf80f4bSopenharmony_ci                             ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT;
1118bf80f4bSopenharmony_ci    resolveDesc.imageType = ImageType::CORE_IMAGE_TYPE_2D;
1128bf80f4bSopenharmony_ci    resolveDesc.imageTiling = ImageTiling::CORE_IMAGE_TILING_OPTIMAL;
1138bf80f4bSopenharmony_ci    resolveDesc.imageViewType = ImageViewType::CORE_IMAGE_VIEW_TYPE_2D;
1148bf80f4bSopenharmony_ci    resolveDesc.engineCreationFlags = EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS;
1158bf80f4bSopenharmony_ci    return resolveDesc;
1168bf80f4bSopenharmony_ci}
1178bf80f4bSopenharmony_ci
1188bf80f4bSopenharmony_cistatic BASE_NS::string ROOTNODE_NAME = "rootNode_";
1198bf80f4bSopenharmony_cistatic BASE_NS::string ROOTNODE_PATH = "/" + ROOTNODE_NAME + "/";
1208bf80f4bSopenharmony_ci
1218bf80f4bSopenharmony_ciBASE_NS::string_view RemoveRootNodeFromPath(const BASE_NS::string_view& path)
1228bf80f4bSopenharmony_ci{
1238bf80f4bSopenharmony_ci    if (path.starts_with(ROOTNODE_PATH)) {
1248bf80f4bSopenharmony_ci        return path.substr(ROOTNODE_PATH.length());
1258bf80f4bSopenharmony_ci    }
1268bf80f4bSopenharmony_ci
1278bf80f4bSopenharmony_ci    if (path.starts_with("/")) {
1288bf80f4bSopenharmony_ci        return path.substr(1);
1298bf80f4bSopenharmony_ci    }
1308bf80f4bSopenharmony_ci
1318bf80f4bSopenharmony_ci    return path;
1328bf80f4bSopenharmony_ci}
1338bf80f4bSopenharmony_ci} // namespace
1348bf80f4bSopenharmony_ci
1358bf80f4bSopenharmony_ciSceneHolder::SceneHolder(META_NS::InstanceId uid, META_NS::IObjectRegistry& registry,
1368bf80f4bSopenharmony_ci    const BASE_NS::shared_ptr<RENDER_NS::IRenderContext>& gc, META_NS::ITaskQueue::Ptr appQueue,
1378bf80f4bSopenharmony_ci    META_NS::ITaskQueue::Ptr engineQueue)
1388bf80f4bSopenharmony_ci    : instanceId_(uid), renderContext_(gc), appTaskQueue_(appQueue), engineTaskQueue_(engineQueue),
1398bf80f4bSopenharmony_ci      objectRegistry_(registry)
1408bf80f4bSopenharmony_ci{}
1418bf80f4bSopenharmony_ci
1428bf80f4bSopenharmony_ciSceneHolder::~SceneHolder()
1438bf80f4bSopenharmony_ci{
1448bf80f4bSopenharmony_ci    ResetScene(false);
1458bf80f4bSopenharmony_ci}
1468bf80f4bSopenharmony_ci
1478bf80f4bSopenharmony_ciCORE_NS::IEcs::Ptr SceneHolder::GetEcs()
1488bf80f4bSopenharmony_ci{
1498bf80f4bSopenharmony_ci    // once we offer Ecs to anyone, we cannot know it is intact
1508bf80f4bSopenharmony_ci    scenePrepared_ = false;
1518bf80f4bSopenharmony_ci    return ecs_;
1528bf80f4bSopenharmony_ci}
1538bf80f4bSopenharmony_ci
1548bf80f4bSopenharmony_civoid SceneHolder::Initialize(WeakPtr me)
1558bf80f4bSopenharmony_ci{
1568bf80f4bSopenharmony_ci    me_ = me;
1578bf80f4bSopenharmony_ci    InitializeScene();
1588bf80f4bSopenharmony_ci}
1598bf80f4bSopenharmony_ci
1608bf80f4bSopenharmony_civoid SceneHolder::Uninitialize()
1618bf80f4bSopenharmony_ci{
1628bf80f4bSopenharmony_ci    // Remove callbacks, these are no longer needed.
1638bf80f4bSopenharmony_ci    SetInitializeCallback({}, me_);
1648bf80f4bSopenharmony_ci    SetSceneLoadedCallback({}, me_);
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_ci    // Move processing to engine thread.
1678bf80f4bSopenharmony_ci    UninitializeScene();
1688bf80f4bSopenharmony_ci}
1698bf80f4bSopenharmony_civoid SceneHolder::SetRenderSize(uint32_t width, uint32_t height, uint64_t cameraHandle)
1708bf80f4bSopenharmony_ci{
1718bf80f4bSopenharmony_ci    // Render size changed, schedule update engine thread.
1728bf80f4bSopenharmony_ci    UpdateViewportSize(width, height, cameraHandle);
1738bf80f4bSopenharmony_ci}
1748bf80f4bSopenharmony_ci
1758bf80f4bSopenharmony_civoid SceneHolder::SetCameraTarget(
1768bf80f4bSopenharmony_ci    const SCENE_NS::ICamera::Ptr& camera, BASE_NS::Math::UVec2 size, RENDER_NS::RenderHandleReference ref)
1778bf80f4bSopenharmony_ci{
1788bf80f4bSopenharmony_ci    auto cameraEnt = interface_cast<SCENE_NS::IEcsObject>(camera)->GetEntity();
1798bf80f4bSopenharmony_ci
1808bf80f4bSopenharmony_ci    CameraData::Ptr cd;
1818bf80f4bSopenharmony_ci    for (auto c : cameras_) {
1828bf80f4bSopenharmony_ci        if (c->entity == cameraEnt) {
1838bf80f4bSopenharmony_ci            cd = c;
1848bf80f4bSopenharmony_ci            break;
1858bf80f4bSopenharmony_ci        }
1868bf80f4bSopenharmony_ci    }
1878bf80f4bSopenharmony_ci    if (!cd) {
1888bf80f4bSopenharmony_ci        // invalid.
1898bf80f4bSopenharmony_ci        return;
1908bf80f4bSopenharmony_ci    }
1918bf80f4bSopenharmony_ci    cd->width = size.x;
1928bf80f4bSopenharmony_ci    cd->height = size.y;
1938bf80f4bSopenharmony_ci    if (!ref) {
1948bf80f4bSopenharmony_ci        cd->colorImage = {};
1958bf80f4bSopenharmony_ci        cd->ownsColorImage = true;
1968bf80f4bSopenharmony_ci        RecreateOutputTexture(cd);
1978bf80f4bSopenharmony_ci    } else {
1988bf80f4bSopenharmony_ci        cd->colorImage = ref;
1998bf80f4bSopenharmony_ci        cd->ownsColorImage = false;
2008bf80f4bSopenharmony_ci    }
2018bf80f4bSopenharmony_ci    cd->updateTargets = true;
2028bf80f4bSopenharmony_ci}
2038bf80f4bSopenharmony_ci
2048bf80f4bSopenharmony_civoid SceneHolder::RequestReload()
2058bf80f4bSopenharmony_ci{
2068bf80f4bSopenharmony_ci    LoadScene();
2078bf80f4bSopenharmony_ci}
2088bf80f4bSopenharmony_ci
2098bf80f4bSopenharmony_civoid SceneHolder::Load(const BASE_NS::string& uri)
2108bf80f4bSopenharmony_ci{
2118bf80f4bSopenharmony_ci    // Scene systems graph uri changed, schedule update to engine thread.
2128bf80f4bSopenharmony_ci    if (sceneUri_ != uri) {
2138bf80f4bSopenharmony_ci        sceneUri_ = uri;
2148bf80f4bSopenharmony_ci
2158bf80f4bSopenharmony_ci        RequestReload();
2168bf80f4bSopenharmony_ci    }
2178bf80f4bSopenharmony_ci}
2188bf80f4bSopenharmony_ci
2198bf80f4bSopenharmony_civoid SceneHolder::SetSystemGraphUri(const string& uri)
2208bf80f4bSopenharmony_ci{
2218bf80f4bSopenharmony_ci    // Scene systems graph uri changed, schedule update to engine thread.
2228bf80f4bSopenharmony_ci    if (uri != sceneSystemGraphUri_) {
2238bf80f4bSopenharmony_ci        sceneSystemGraphUri_ = uri;
2248bf80f4bSopenharmony_ci
2258bf80f4bSopenharmony_ci        RequestReload();
2268bf80f4bSopenharmony_ci    }
2278bf80f4bSopenharmony_ci}
2288bf80f4bSopenharmony_ci
2298bf80f4bSopenharmony_civoid SceneHolder::SetInitializeCallback(ISceneInitialized::Ptr callback, SceneHolder::WeakPtr weakMe)
2308bf80f4bSopenharmony_ci{
2318bf80f4bSopenharmony_ci    // Schedule update of callback to engine thread.
2328bf80f4bSopenharmony_ci    sceneInitializedCallback_ = callback;
2338bf80f4bSopenharmony_ci}
2348bf80f4bSopenharmony_ci
2358bf80f4bSopenharmony_civoid SceneHolder::SetSceneLoadedCallback(ISceneLoaded::Ptr callback, SceneHolder::WeakPtr weakMe)
2368bf80f4bSopenharmony_ci{
2378bf80f4bSopenharmony_ci    // Schedule update of callback to engine thread.
2388bf80f4bSopenharmony_ci    sceneLoadedCallback_ = callback;
2398bf80f4bSopenharmony_ci}
2408bf80f4bSopenharmony_ci
2418bf80f4bSopenharmony_civoid SceneHolder::SetUninitializeCallback(ISceneUninitialized::Ptr callback, SceneHolder::WeakPtr weakMe)
2428bf80f4bSopenharmony_ci{
2438bf80f4bSopenharmony_ci    // Schedule update of callback to engine thread.
2448bf80f4bSopenharmony_ci    sceneUninitializedCallback_ = callback;
2458bf80f4bSopenharmony_ci}
2468bf80f4bSopenharmony_ci
2478bf80f4bSopenharmony_civoid SceneHolder::ActivateCamera(const Entity& cameraEntity) const
2488bf80f4bSopenharmony_ci{
2498bf80f4bSopenharmony_ci    if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
2508bf80f4bSopenharmony_ci        CORE_LOG_W("SceneHolder::ActivateCamera: Can not be activated. cameraEntity: %" PRIx64
2518bf80f4bSopenharmony_ci                   ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
2528bf80f4bSopenharmony_ci            cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
2538bf80f4bSopenharmony_ci        return;
2548bf80f4bSopenharmony_ci    }
2558bf80f4bSopenharmony_ci
2568bf80f4bSopenharmony_ci    CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
2578bf80f4bSopenharmony_ci    cameraComponent.sceneFlags |= CameraComponent::ACTIVE_RENDER_BIT;
2588bf80f4bSopenharmony_ci    cameraComponentManager_->Set(cameraEntity, cameraComponent);
2598bf80f4bSopenharmony_ci}
2608bf80f4bSopenharmony_ci
2618bf80f4bSopenharmony_civoid SceneHolder::DeactivateCamera(const Entity& cameraEntity) const
2628bf80f4bSopenharmony_ci{
2638bf80f4bSopenharmony_ci    if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
2648bf80f4bSopenharmony_ci        CORE_LOG_W("SceneHolder::DeactivateCamera: Can not be deactivated. cameraEntity: %" PRIx64
2658bf80f4bSopenharmony_ci                   ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
2668bf80f4bSopenharmony_ci            cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
2678bf80f4bSopenharmony_ci        return;
2688bf80f4bSopenharmony_ci    }
2698bf80f4bSopenharmony_ci
2708bf80f4bSopenharmony_ci    CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
2718bf80f4bSopenharmony_ci    cameraComponent.sceneFlags &= ~(CameraComponent::ACTIVE_RENDER_BIT /* | CameraComponent::MAIN_CAMERA_BIT*/);
2728bf80f4bSopenharmony_ci    cameraComponentManager_->Set(cameraEntity, cameraComponent);
2738bf80f4bSopenharmony_ci}
2748bf80f4bSopenharmony_ci
2758bf80f4bSopenharmony_cibool SceneHolder::IsCameraActive(const Entity& cameraEntity) const
2768bf80f4bSopenharmony_ci{
2778bf80f4bSopenharmony_ci    if (!(cameraComponentManager_ && EntityUtil::IsValid(cameraEntity))) {
2788bf80f4bSopenharmony_ci        CORE_LOG_W("SceneHolder::DeactivateCamera: Can not be deactivated. cameraEntity: %" PRIx64
2798bf80f4bSopenharmony_ci                   ", cameraComponentManager_: %d, IsValid(cameraEntity): %d",
2808bf80f4bSopenharmony_ci            cameraEntity.id, static_cast<bool>(cameraComponentManager_), EntityUtil::IsValid(cameraEntity));
2818bf80f4bSopenharmony_ci        return false;
2828bf80f4bSopenharmony_ci    }
2838bf80f4bSopenharmony_ci
2848bf80f4bSopenharmony_ci    CameraComponent cameraComponent = cameraComponentManager_->Get(cameraEntity);
2858bf80f4bSopenharmony_ci    return cameraComponent.sceneFlags & (CameraComponent::ACTIVE_RENDER_BIT);
2868bf80f4bSopenharmony_ci}
2878bf80f4bSopenharmony_ci
2888bf80f4bSopenharmony_cibool SceneHolder::InitializeScene()
2898bf80f4bSopenharmony_ci{
2908bf80f4bSopenharmony_ci    graphicsContext3D_ = CreateInstance<CORE3D_NS::IGraphicsContext>(
2918bf80f4bSopenharmony_ci        *renderContext_->GetInterface<IClassFactory>(), UID_GRAPHICS_CONTEXT);
2928bf80f4bSopenharmony_ci    graphicsContext3D_->Init();
2938bf80f4bSopenharmony_ci
2948bf80f4bSopenharmony_ci    picking_ = GetInstance<CORE3D_NS::IPicking>(*renderContext_->GetInterface<IClassRegister>(), UID_PICKING);
2958bf80f4bSopenharmony_ci
2968bf80f4bSopenharmony_ci    // scene loading was attempted before initialization, retry now
2978bf80f4bSopenharmony_ci    if (loadSceneFailed_) {
2988bf80f4bSopenharmony_ci        loadSceneFailed_ = false;
2998bf80f4bSopenharmony_ci        RequestReload();
3008bf80f4bSopenharmony_ci    } else {
3018bf80f4bSopenharmony_ci        // business as usual, set up things according build time settings
3028bf80f4bSopenharmony_ci#ifdef INITIALIZE_ECS_IMMEDIATELY
3038bf80f4bSopenharmony_ci        ResetScene(true);
3048bf80f4bSopenharmony_ci        scenePrepared_ = true;
3058bf80f4bSopenharmony_ci#else
3068bf80f4bSopenharmony_ci        ResetScene(false);
3078bf80f4bSopenharmony_ci#endif
3088bf80f4bSopenharmony_ci    }
3098bf80f4bSopenharmony_ci
3108bf80f4bSopenharmony_ci    // This is one-time init.
3118bf80f4bSopenharmony_ci    return false;
3128bf80f4bSopenharmony_ci}
3138bf80f4bSopenharmony_ci
3148bf80f4bSopenharmony_ciBASE_NS::vector<CORE_NS::Entity> SceneHolder::RenderCameras()
3158bf80f4bSopenharmony_ci{
3168bf80f4bSopenharmony_ci    // nobody has asked for updates, yet
3178bf80f4bSopenharmony_ci    if (!ecs_ /*|| isReadyForNewFrame_.empty()*/) {
3188bf80f4bSopenharmony_ci        return {};
3198bf80f4bSopenharmony_ci    }
3208bf80f4bSopenharmony_ci
3218bf80f4bSopenharmony_ci    bool busy = false;
3228bf80f4bSopenharmony_ci    BASE_NS::vector<CORE_NS::Entity> activeCameras;
3238bf80f4bSopenharmony_ci    for (auto& camera : cameras_) {
3248bf80f4bSopenharmony_ci        if (!EntityUtil::IsValid(camera->entity))
3258bf80f4bSopenharmony_ci            continue;
3268bf80f4bSopenharmony_ci
3278bf80f4bSopenharmony_ci        if (auto cc = cameraComponentManager_->Read(camera->entity)) {
3288bf80f4bSopenharmony_ci            if (cc->sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) {
3298bf80f4bSopenharmony_ci                if (camera->updateTargets) {
3308bf80f4bSopenharmony_ci                    UpdateCameraRenderTarget(camera);
3318bf80f4bSopenharmony_ci                    camera->updateTargets = false;
3328bf80f4bSopenharmony_ci                }
3338bf80f4bSopenharmony_ci                activeCameras.push_back(camera->entity);
3348bf80f4bSopenharmony_ci            }
3358bf80f4bSopenharmony_ci        }
3368bf80f4bSopenharmony_ci    }
3378bf80f4bSopenharmony_ci    isRunningFrame_ = true;
3388bf80f4bSopenharmony_ci    // Tick frame. One camera could have static view while other is moving
3398bf80f4bSopenharmony_ci    IEcs* ecs = ecs_.get();
3408bf80f4bSopenharmony_ci    ecs->ProcessEvents();
3418bf80f4bSopenharmony_ci    using namespace std::chrono;
3428bf80f4bSopenharmony_ci    const auto currentTime =
3438bf80f4bSopenharmony_ci        static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
3448bf80f4bSopenharmony_ci    if (firstTime_ == ~0u) {
3458bf80f4bSopenharmony_ci        previousFrameTime_ = firstTime_ = currentTime;
3468bf80f4bSopenharmony_ci    }
3478bf80f4bSopenharmony_ci    auto deltaTime = currentTime - previousFrameTime_;
3488bf80f4bSopenharmony_ci    constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
3498bf80f4bSopenharmony_ci    if (deltaTime > limitHz) {
3508bf80f4bSopenharmony_ci        deltaTime = limitHz; // clampthe time step to no longer than 15hz.
3518bf80f4bSopenharmony_ci    }
3528bf80f4bSopenharmony_ci    previousFrameTime_ = currentTime;
3538bf80f4bSopenharmony_ci    const uint64_t totalTime = currentTime - firstTime_;
3548bf80f4bSopenharmony_ci    const bool needsRender = ecs->Update(totalTime, deltaTime);
3558bf80f4bSopenharmony_ci    ecs->ProcessEvents();
3568bf80f4bSopenharmony_ci    auto renderHandles = graphicsContext3D_->GetRenderNodeGraphs(*ecs_);
3578bf80f4bSopenharmony_ci
3588bf80f4bSopenharmony_ci    if ((needsRender) && (!renderHandles.empty())) {
3598bf80f4bSopenharmony_ci        // The scene needs to be rendered.
3608bf80f4bSopenharmony_ci        RENDER_NS::IRenderer& renderer = renderContext_->GetRenderer();
3618bf80f4bSopenharmony_ci        renderer.RenderDeferred(renderHandles);
3628bf80f4bSopenharmony_ci    } else {
3638bf80f4bSopenharmony_ci        // did not render anything.
3648bf80f4bSopenharmony_ci        bool nr = needsRender;
3658bf80f4bSopenharmony_ci        activeCameras.clear();
3668bf80f4bSopenharmony_ci    }
3678bf80f4bSopenharmony_ci    isRunningFrame_ = false;
3688bf80f4bSopenharmony_ci
3698bf80f4bSopenharmony_ci    if (requiresEventProcessing_) {
3708bf80f4bSopenharmony_ci        ProcessEvents();
3718bf80f4bSopenharmony_ci    }
3728bf80f4bSopenharmony_ci
3738bf80f4bSopenharmony_ci    // Schedule new update to scene.
3748bf80f4bSopenharmony_ci    return activeCameras;
3758bf80f4bSopenharmony_ci}
3768bf80f4bSopenharmony_ci
3778bf80f4bSopenharmony_cibool SceneHolder::UninitializeScene()
3788bf80f4bSopenharmony_ci{
3798bf80f4bSopenharmony_ci    ResetScene();
3808bf80f4bSopenharmony_ci
3818bf80f4bSopenharmony_ci    if (ecs_) {
3828bf80f4bSopenharmony_ci        ecs_->Uninitialize();
3838bf80f4bSopenharmony_ci        ecs_.reset();
3848bf80f4bSopenharmony_ci    }
3858bf80f4bSopenharmony_ci
3868bf80f4bSopenharmony_ci    if (sceneUninitializedCallback_) {
3878bf80f4bSopenharmony_ci        QueueApplicationTask(MakeTask(
3888bf80f4bSopenharmony_ci                                 [](auto callback) {
3898bf80f4bSopenharmony_ci                                     callback->Invoke();
3908bf80f4bSopenharmony_ci                                     return false;
3918bf80f4bSopenharmony_ci                                 },
3928bf80f4bSopenharmony_ci                                 sceneUninitializedCallback_),
3938bf80f4bSopenharmony_ci            false);
3948bf80f4bSopenharmony_ci    }
3958bf80f4bSopenharmony_ci
3968bf80f4bSopenharmony_ci    sceneInitializedCallback_.reset();
3978bf80f4bSopenharmony_ci    sceneUpdatedCallback_.reset();
3988bf80f4bSopenharmony_ci    sceneUninitializedCallback_.reset();
3998bf80f4bSopenharmony_ci
4008bf80f4bSopenharmony_ci    return false;
4018bf80f4bSopenharmony_ci}
4028bf80f4bSopenharmony_ci
4038bf80f4bSopenharmony_civoid SceneHolder::ProcessEvents()
4048bf80f4bSopenharmony_ci{
4058bf80f4bSopenharmony_ci    if (isRunningFrame_) {
4068bf80f4bSopenharmony_ci        requiresEventProcessing_ = true;
4078bf80f4bSopenharmony_ci        return;
4088bf80f4bSopenharmony_ci    }
4098bf80f4bSopenharmony_ci
4108bf80f4bSopenharmony_ci    if (ecsListener_ && ecsListener_->IsCallbackActive()) {
4118bf80f4bSopenharmony_ci        requiresEventProcessing_ = true;
4128bf80f4bSopenharmony_ci        return;
4138bf80f4bSopenharmony_ci    }
4148bf80f4bSopenharmony_ci
4158bf80f4bSopenharmony_ci    if (ecs_) {
4168bf80f4bSopenharmony_ci        ecs_->ProcessEvents();
4178bf80f4bSopenharmony_ci        requiresEventProcessing_ = false;
4188bf80f4bSopenharmony_ci    }
4198bf80f4bSopenharmony_ci}
4208bf80f4bSopenharmony_ci
4218bf80f4bSopenharmony_cibool SceneHolder::CreateDefaultEcs()
4228bf80f4bSopenharmony_ci{
4238bf80f4bSopenharmony_ci    if (!renderContext_) {
4248bf80f4bSopenharmony_ci        CORE_LOG_W("%s: Graphics contexts is not available, can not create ecs", __func__);
4258bf80f4bSopenharmony_ci        return false;
4268bf80f4bSopenharmony_ci    }
4278bf80f4bSopenharmony_ci
4288bf80f4bSopenharmony_ci    auto& engine = renderContext_->GetEngine();
4298bf80f4bSopenharmony_ci
4308bf80f4bSopenharmony_ci    ecs_ = engine.CreateEcs();
4318bf80f4bSopenharmony_ci    ecs_->SetRenderMode(renderMode_);
4328bf80f4bSopenharmony_ci
4338bf80f4bSopenharmony_ci    if (!ecsListener_) {
4348bf80f4bSopenharmony_ci        ecsListener_ = BASE_NS::shared_ptr<SCENE_NS::EcsListener>(new SCENE_NS::EcsListener());
4358bf80f4bSopenharmony_ci    }
4368bf80f4bSopenharmony_ci    ecsListener_->SetEcs(ecs_);
4378bf80f4bSopenharmony_ci
4388bf80f4bSopenharmony_ci    // Get systemGraphLoader factory from global plugin registry.
4398bf80f4bSopenharmony_ci    auto* factory = GetInstance<ISystemGraphLoaderFactory>(UID_SYSTEM_GRAPH_LOADER);
4408bf80f4bSopenharmony_ci    auto systemGraphLoader = factory->Create(engine.GetFileManager());
4418bf80f4bSopenharmony_ci
4428bf80f4bSopenharmony_ci    // First try to load project-specific system graph.
4438bf80f4bSopenharmony_ci    auto result = sceneSystemGraphUri_.empty() ? false : systemGraphLoader->Load(sceneSystemGraphUri_, *ecs_).success;
4448bf80f4bSopenharmony_ci
4458bf80f4bSopenharmony_ci    if (!result) {
4468bf80f4bSopenharmony_ci        // Fall back to default graph.
4478bf80f4bSopenharmony_ci        systemGraphLoader->Load("rofs3D://systemGraph.json", *ecs_);
4488bf80f4bSopenharmony_ci    }
4498bf80f4bSopenharmony_ci
4508bf80f4bSopenharmony_ci    auto renderPreprocessorSystem = GetSystem<IRenderPreprocessorSystem>(*ecs_);
4518bf80f4bSopenharmony_ci
4528bf80f4bSopenharmony_ci    string dataStorePrefix = "renderDataStore:" + GetUniqueName();
4538bf80f4bSopenharmony_ci
4548bf80f4bSopenharmony_ci    auto& renderDataStoreManager = renderContext_->GetRenderDataStoreManager();
4558bf80f4bSopenharmony_ci
4568bf80f4bSopenharmony_ci    auto sceneDataStore = dataStorePrefix + "RenderDataStoreDefaultScene";
4578bf80f4bSopenharmony_ci    auto cameraDataStore = dataStorePrefix + "RenderDataStoreDefaultCamera";
4588bf80f4bSopenharmony_ci    auto lightDataStore = dataStorePrefix + "RenderDataStoreDefaultLight";
4598bf80f4bSopenharmony_ci    auto materialDataStore = dataStorePrefix + "RenderDataStoreDefaultMaterial";
4608bf80f4bSopenharmony_ci    auto morphDataStore = dataStorePrefix + "RenderDataStoreMorph";
4618bf80f4bSopenharmony_ci
4628bf80f4bSopenharmony_ci    if (renderPreprocessorSystem) {
4638bf80f4bSopenharmony_ci        IRenderPreprocessorSystem::Properties props;
4648bf80f4bSopenharmony_ci        props.dataStorePrefix = dataStorePrefix;
4658bf80f4bSopenharmony_ci        props.dataStoreScene = sceneDataStore;
4668bf80f4bSopenharmony_ci        props.dataStoreCamera = cameraDataStore;
4678bf80f4bSopenharmony_ci        props.dataStoreLight = lightDataStore;
4688bf80f4bSopenharmony_ci        props.dataStoreMaterial = materialDataStore;
4698bf80f4bSopenharmony_ci        props.dataStoreMorph = morphDataStore;
4708bf80f4bSopenharmony_ci
4718bf80f4bSopenharmony_ci        *ScopedHandle<IRenderPreprocessorSystem::Properties>(renderPreprocessorSystem->GetProperties()) = props;
4728bf80f4bSopenharmony_ci    }
4738bf80f4bSopenharmony_ci
4748bf80f4bSopenharmony_ci    if (auto callback = ecsInitializationCallback_.lock()) {
4758bf80f4bSopenharmony_ci        auto result = callback->Invoke(ecs_);
4768bf80f4bSopenharmony_ci        if (!result) {
4778bf80f4bSopenharmony_ci            CORE_LOG_W("Ecs initialization failed in the callback, expect trouble");
4788bf80f4bSopenharmony_ci        }
4798bf80f4bSopenharmony_ci    }
4808bf80f4bSopenharmony_ci
4818bf80f4bSopenharmony_ci    ecs_->Initialize();
4828bf80f4bSopenharmony_ci
4838bf80f4bSopenharmony_ci    animationComponentManager_ = CORE_NS::GetManager<CORE3D_NS::IAnimationComponentManager>(*ecs_);
4848bf80f4bSopenharmony_ci    cameraComponentManager_ = GetManager<CORE3D_NS::ICameraComponentManager>(*ecs_);
4858bf80f4bSopenharmony_ci    envComponentManager_ = GetManager<CORE3D_NS::IEnvironmentComponentManager>(*ecs_);
4868bf80f4bSopenharmony_ci    layerComponentManager_ = GetManager<CORE3D_NS::ILayerComponentManager>(*ecs_);
4878bf80f4bSopenharmony_ci    lightComponentManager_ = GetManager<CORE3D_NS::ILightComponentManager>(*ecs_);
4888bf80f4bSopenharmony_ci    materialComponentManager_ = GetManager<CORE3D_NS::IMaterialComponentManager>(*ecs_);
4898bf80f4bSopenharmony_ci    meshComponentManager_ = GetManager<CORE3D_NS::IMeshComponentManager>(*ecs_);
4908bf80f4bSopenharmony_ci    nameComponentManager_ = GetManager<CORE3D_NS::INameComponentManager>(*ecs_);
4918bf80f4bSopenharmony_ci    nodeComponentManager_ = GetManager<CORE3D_NS::INodeComponentManager>(*ecs_);
4928bf80f4bSopenharmony_ci    renderMeshComponentManager_ = GetManager<CORE3D_NS::IRenderMeshComponentManager>(*ecs_);
4938bf80f4bSopenharmony_ci    rhComponentManager_ = GetManager<CORE3D_NS::IRenderHandleComponentManager>(*ecs_);
4948bf80f4bSopenharmony_ci    transformComponentManager_ = GetManager<CORE3D_NS::ITransformComponentManager>(*ecs_);
4958bf80f4bSopenharmony_ci    uriComponentManager_ = GetManager<CORE3D_NS::IUriComponentManager>(*ecs_);
4968bf80f4bSopenharmony_ci
4978bf80f4bSopenharmony_ci    if (animationComponentManager_) {
4988bf80f4bSopenharmony_ci        animationQuery_.reset(new CORE_NS::ComponentQuery());
4998bf80f4bSopenharmony_ci        animationQuery_->SetEcsListenersEnabled(true);
5008bf80f4bSopenharmony_ci        const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
5018bf80f4bSopenharmony_ci                                                             ComponentQuery::Operation::OPTIONAL },
5028bf80f4bSopenharmony_ci            { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL } };
5038bf80f4bSopenharmony_ci        animationQuery_->SetupQuery(*animationComponentManager_, operations);
5048bf80f4bSopenharmony_ci    }
5058bf80f4bSopenharmony_ci
5068bf80f4bSopenharmony_ci    if (meshComponentManager_) {
5078bf80f4bSopenharmony_ci        meshQuery_.reset(new CORE_NS::ComponentQuery());
5088bf80f4bSopenharmony_ci        meshQuery_->SetEcsListenersEnabled(true);
5098bf80f4bSopenharmony_ci        const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
5108bf80f4bSopenharmony_ci                                                             ComponentQuery::Operation::OPTIONAL },
5118bf80f4bSopenharmony_ci            { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL } };
5128bf80f4bSopenharmony_ci        meshQuery_->SetupQuery(*meshComponentManager_, operations);
5138bf80f4bSopenharmony_ci    }
5148bf80f4bSopenharmony_ci
5158bf80f4bSopenharmony_ci    if (materialComponentManager_) {
5168bf80f4bSopenharmony_ci        materialQuery_.reset(new CORE_NS::ComponentQuery());
5178bf80f4bSopenharmony_ci        materialQuery_->SetEcsListenersEnabled(true);
5188bf80f4bSopenharmony_ci        const ComponentQuery::Operation operations[] = { { *nodeComponentManager_,
5198bf80f4bSopenharmony_ci                                                             ComponentQuery::Operation::OPTIONAL },
5208bf80f4bSopenharmony_ci            { *nameComponentManager_, ComponentQuery::Operation::OPTIONAL },
5218bf80f4bSopenharmony_ci            { *uriComponentManager_, ComponentQuery::Operation::OPTIONAL } };
5228bf80f4bSopenharmony_ci        materialQuery_->SetupQuery(*materialComponentManager_, operations);
5238bf80f4bSopenharmony_ci    }
5248bf80f4bSopenharmony_ci    nodeSystem_ = static_cast<CORE3D_NS::INodeSystem*>(ecs_->GetSystem(CORE3D_NS::INodeSystem::UID));
5258bf80f4bSopenharmony_ci    return true;
5268bf80f4bSopenharmony_ci}
5278bf80f4bSopenharmony_ci
5288bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateCamera(const BASE_NS::string& name, uint32_t flagBits)
5298bf80f4bSopenharmony_ci{
5308bf80f4bSopenharmony_ci    return CreateCamera({}, name, flagBits);
5318bf80f4bSopenharmony_ci}
5328bf80f4bSopenharmony_ci
5338bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateCamera(const BASE_NS::string& path, const BASE_NS::string& name, uint32_t flagBits)
5348bf80f4bSopenharmony_ci{
5358bf80f4bSopenharmony_ci    if (ecs_) {
5368bf80f4bSopenharmony_ci        auto pathWithoutRootNode = RemoveRootNodeFromPath(path);
5378bf80f4bSopenharmony_ci
5388bf80f4bSopenharmony_ci        // Create camera. Scene util produces an invalid node so set up our camera from node system ourself
5398bf80f4bSopenharmony_ci        auto nodeSystem = GetSystem<INodeSystem>(*ecs_);
5408bf80f4bSopenharmony_ci        auto node = nodeSystem->CreateNode();
5418bf80f4bSopenharmony_ci        auto entity = node->GetEntity();
5428bf80f4bSopenharmony_ci
5438bf80f4bSopenharmony_ci        CORE3D_NS::ISceneNode* parent = nullptr;
5448bf80f4bSopenharmony_ci        if (pathWithoutRootNode.empty()) {
5458bf80f4bSopenharmony_ci            parent = rootNode_;
5468bf80f4bSopenharmony_ci        } else {
5478bf80f4bSopenharmony_ci            parent = rootNode_->LookupNodeByPath(pathWithoutRootNode);
5488bf80f4bSopenharmony_ci        }
5498bf80f4bSopenharmony_ci
5508bf80f4bSopenharmony_ci        CORE_ASSERT(parent);
5518bf80f4bSopenharmony_ci
5528bf80f4bSopenharmony_ci        node->SetParent(*parent);
5538bf80f4bSopenharmony_ci        node->SetName(name);
5548bf80f4bSopenharmony_ci
5558bf80f4bSopenharmony_ci        auto tcm = GetManager<ITransformComponentManager>(*ecs_);
5568bf80f4bSopenharmony_ci        TransformComponent tc;
5578bf80f4bSopenharmony_ci        tc.position = Math::Vec3(0.0f, 0.0f, 2.5f);
5588bf80f4bSopenharmony_ci        tc.rotation = {};
5598bf80f4bSopenharmony_ci        tcm->Set(entity, tc);
5608bf80f4bSopenharmony_ci
5618bf80f4bSopenharmony_ci        CameraComponent cc;
5628bf80f4bSopenharmony_ci        cc.sceneFlags |= CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT;
5638bf80f4bSopenharmony_ci        cc.projection = CameraComponent::Projection::PERSPECTIVE;
5648bf80f4bSopenharmony_ci        cc.yFov = Math::DEG2RAD * 60.f;
5658bf80f4bSopenharmony_ci        cc.zNear = 0.1f;
5668bf80f4bSopenharmony_ci        cc.zFar = 100.f;
5678bf80f4bSopenharmony_ci        cc.sceneFlags |= flagBits;
5688bf80f4bSopenharmony_ci        cameraComponentManager_->Set(entity, cc);
5698bf80f4bSopenharmony_ci
5708bf80f4bSopenharmony_ci        cameras_.emplace_back(CameraData::Create(entity));
5718bf80f4bSopenharmony_ci        return entity;
5728bf80f4bSopenharmony_ci    } else {
5738bf80f4bSopenharmony_ci        CORE_LOG_E("%s: Ecs not available, can not create camera %s", __func__, name.c_str());
5748bf80f4bSopenharmony_ci    }
5758bf80f4bSopenharmony_ci    return CORE_NS::Entity();
5768bf80f4bSopenharmony_ci}
5778bf80f4bSopenharmony_ci
5788bf80f4bSopenharmony_civoid SceneHolder::SetDefaultCamera()
5798bf80f4bSopenharmony_ci{
5808bf80f4bSopenharmony_ci    if (cameraComponentManager_) {
5818bf80f4bSopenharmony_ci        auto cameraCount = cameraComponentManager_->GetComponentCount();
5828bf80f4bSopenharmony_ci        while (cameraCount) {
5838bf80f4bSopenharmony_ci            --cameraCount;
5848bf80f4bSopenharmony_ci            // if the scene already contains main camera, respect it
5858bf80f4bSopenharmony_ci            if (cameraComponentManager_->Get(cameraComponentManager_->GetEntity(cameraCount)).sceneFlags &
5868bf80f4bSopenharmony_ci                CameraComponent::MAIN_CAMERA_BIT) {
5878bf80f4bSopenharmony_ci                auto entity = cameraComponentManager_->GetEntity(cameraCount);
5888bf80f4bSopenharmony_ci                cameras_.emplace_back(CameraData::Create(entity));
5898bf80f4bSopenharmony_ci                defaultCameraEntity_ = entity;
5908bf80f4bSopenharmony_ci                SetMainCamera(entity);
5918bf80f4bSopenharmony_ci                return;
5928bf80f4bSopenharmony_ci            }
5938bf80f4bSopenharmony_ci        }
5948bf80f4bSopenharmony_ci    }
5958bf80f4bSopenharmony_ci}
5968bf80f4bSopenharmony_ci
5978bf80f4bSopenharmony_civoid SceneHolder::SetMainCamera(const Entity& entity)
5988bf80f4bSopenharmony_ci{
5998bf80f4bSopenharmony_ci    if (cameras_.empty() || (mainCamera_ && entity == mainCamera_->entity)) {
6008bf80f4bSopenharmony_ci        return;
6018bf80f4bSopenharmony_ci    }
6028bf80f4bSopenharmony_ci
6038bf80f4bSopenharmony_ci    if (mainCamera_ && cameraComponentManager_ && EntityUtil::IsValid(mainCamera_->entity)) {
6048bf80f4bSopenharmony_ci        bool isAlive = ecs_->GetEntityManager().IsAlive(mainCamera_->entity);
6058bf80f4bSopenharmony_ci        if (isAlive) {
6068bf80f4bSopenharmony_ci            // Mark previous main camera as inactive.
6078bf80f4bSopenharmony_ci            CameraComponent cameraComponent = cameraComponentManager_->Get(mainCamera_->entity);
6088bf80f4bSopenharmony_ci            cameraComponent.sceneFlags &= ~CameraComponent::MAIN_CAMERA_BIT;
6098bf80f4bSopenharmony_ci            cameraComponentManager_->Set(mainCamera_->entity, cameraComponent);
6108bf80f4bSopenharmony_ci        }
6118bf80f4bSopenharmony_ci    }
6128bf80f4bSopenharmony_ci
6138bf80f4bSopenharmony_ci    mainCamera_ = {};
6148bf80f4bSopenharmony_ci
6158bf80f4bSopenharmony_ci    for (auto& camera : cameras_) {
6168bf80f4bSopenharmony_ci        if (camera->entity == entity) {
6178bf80f4bSopenharmony_ci            mainCamera_ = camera;
6188bf80f4bSopenharmony_ci            break;
6198bf80f4bSopenharmony_ci        }
6208bf80f4bSopenharmony_ci    }
6218bf80f4bSopenharmony_ci
6228bf80f4bSopenharmony_ci    if (!mainCamera_) {
6238bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
6248bf80f4bSopenharmony_ci            CORE_LOG_W("%s: was not able to set camera for: %" PRIx64 " ", __func__, entity.id);
6258bf80f4bSopenharmony_ci        }
6268bf80f4bSopenharmony_ci        return;
6278bf80f4bSopenharmony_ci    }
6288bf80f4bSopenharmony_ci
6298bf80f4bSopenharmony_ci    if (cameraComponentManager_ && EntityUtil::IsValid(mainCamera_->entity)) {
6308bf80f4bSopenharmony_ci        // Mark new camera as active.
6318bf80f4bSopenharmony_ci        CameraComponent cameraComponent = cameraComponentManager_->Get(mainCamera_->entity);
6328bf80f4bSopenharmony_ci        cameraComponent.sceneFlags |= CameraComponent::MAIN_CAMERA_BIT;
6338bf80f4bSopenharmony_ci        cameraComponentManager_->Set(mainCamera_->entity, cameraComponent);
6348bf80f4bSopenharmony_ci        UpdateViewportSize(mainCamera_->width, mainCamera_->height, mainCamera_->entity.id);
6358bf80f4bSopenharmony_ci    }
6368bf80f4bSopenharmony_ci}
6378bf80f4bSopenharmony_ci
6388bf80f4bSopenharmony_civoid SceneHolder::AddCamera(const CORE_NS::Entity& entity)
6398bf80f4bSopenharmony_ci{
6408bf80f4bSopenharmony_ci    for (auto c : cameras_) {
6418bf80f4bSopenharmony_ci        if (c->entity == entity) {
6428bf80f4bSopenharmony_ci            return;
6438bf80f4bSopenharmony_ci        }
6448bf80f4bSopenharmony_ci    }
6458bf80f4bSopenharmony_ci    cameras_.emplace_back(CameraData::Create(entity));
6468bf80f4bSopenharmony_ci}
6478bf80f4bSopenharmony_ci
6488bf80f4bSopenharmony_civoid SceneHolder::RemoveCamera(const CORE_NS::Entity& entity)
6498bf80f4bSopenharmony_ci{
6508bf80f4bSopenharmony_ci    auto it = std::find_if(cameras_.begin(), cameras_.end(), [entity](const auto& item) {
6518bf80f4bSopenharmony_ci        // Check if camera entities are the same.
6528bf80f4bSopenharmony_ci        return item->entity == entity;
6538bf80f4bSopenharmony_ci    });
6548bf80f4bSopenharmony_ci
6558bf80f4bSopenharmony_ci    if (it != cameras_.end()) {
6568bf80f4bSopenharmony_ci        cameras_.erase(it);
6578bf80f4bSopenharmony_ci    }
6588bf80f4bSopenharmony_ci}
6598bf80f4bSopenharmony_ci
6608bf80f4bSopenharmony_civoid SceneHolder::UpdateViewportSize(uint32_t width, uint32_t height, uint64_t cameraHandle)
6618bf80f4bSopenharmony_ci{
6628bf80f4bSopenharmony_ci    CORE_LOG_D("%s: w: %u h: %u", __func__, width, height);
6638bf80f4bSopenharmony_ci    // these would be never valid as render target so use some default values to make sure that buffers are prepared
6648bf80f4bSopenharmony_ci    if (width == 0) {
6658bf80f4bSopenharmony_ci        width = 128; // 128 default width
6668bf80f4bSopenharmony_ci    }
6678bf80f4bSopenharmony_ci    if (height == 0) {
6688bf80f4bSopenharmony_ci        height = 128; // // 128 default height
6698bf80f4bSopenharmony_ci    }
6708bf80f4bSopenharmony_ci
6718bf80f4bSopenharmony_ci    if (ecs_) {
6728bf80f4bSopenharmony_ci        if (cameraHandle == 0 && !cameras_.empty()) {
6738bf80f4bSopenharmony_ci            // short circuit defaut camera
6748bf80f4bSopenharmony_ci            cameraHandle = cameras_.front()->entity.id;
6758bf80f4bSopenharmony_ci        }
6768bf80f4bSopenharmony_ci
6778bf80f4bSopenharmony_ci        // Make sure that render target will be updated
6788bf80f4bSopenharmony_ci        // ToDo: Clean this up to select the correct camera instance
6798bf80f4bSopenharmony_ci        CameraData::Ptr camera;
6808bf80f4bSopenharmony_ci
6818bf80f4bSopenharmony_ci        for (auto& c : cameras_) {
6828bf80f4bSopenharmony_ci            if (c->entity.id == cameraHandle) {
6838bf80f4bSopenharmony_ci                camera = c;
6848bf80f4bSopenharmony_ci                break;
6858bf80f4bSopenharmony_ci            }
6868bf80f4bSopenharmony_ci        }
6878bf80f4bSopenharmony_ci        if (!camera) {
6888bf80f4bSopenharmony_ci            return;
6898bf80f4bSopenharmony_ci        }
6908bf80f4bSopenharmony_ci        if (!camera->ownsColorImage) {
6918bf80f4bSopenharmony_ci            // we don't own the bitmap so.
6928bf80f4bSopenharmony_ci            return;
6938bf80f4bSopenharmony_ci        }
6948bf80f4bSopenharmony_ci
6958bf80f4bSopenharmony_ci        camera->width = width;
6968bf80f4bSopenharmony_ci        camera->height = height;
6978bf80f4bSopenharmony_ci        RecreateOutputTexture(camera);
6988bf80f4bSopenharmony_ci
6998bf80f4bSopenharmony_ci        if (!EntityUtil::IsValid(camera->entity)) {
7008bf80f4bSopenharmony_ci            return;
7018bf80f4bSopenharmony_ci        }
7028bf80f4bSopenharmony_ci        camera->updateTargets = true;
7038bf80f4bSopenharmony_ci        ecs_->RequestRender();
7048bf80f4bSopenharmony_ci    }
7058bf80f4bSopenharmony_ci}
7068bf80f4bSopenharmony_ci
7078bf80f4bSopenharmony_civoid SceneHolder::RecreateOutputTexture(CameraData::Ptr camera)
7088bf80f4bSopenharmony_ci{
7098bf80f4bSopenharmony_ci    if ((renderContext_) && (camera)) {
7108bf80f4bSopenharmony_ci        if (camera->ownsColorImage) {
7118bf80f4bSopenharmony_ci            camera->colorImage = renderContext_->GetDevice().GetGpuResourceManager().Create(
7128bf80f4bSopenharmony_ci                GetColorImageDesc(camera->width, camera->height));
7138bf80f4bSopenharmony_ci#ifdef SCENE_PLUGIN_CREATE_IMPLICIT_DEPTH_TARGET
7148bf80f4bSopenharmony_ci            camera->depthImage = renderContext_->GetDevice().GetGpuResourceManager().Create(
7158bf80f4bSopenharmony_ci                GetDepthImageDesc(camera->width, camera->height));
7168bf80f4bSopenharmony_ci#endif
7178bf80f4bSopenharmony_ci        }
7188bf80f4bSopenharmony_ci    }
7198bf80f4bSopenharmony_ci}
7208bf80f4bSopenharmony_ci
7218bf80f4bSopenharmony_cibool SceneHolder::UpdateCameraRenderTarget(CameraData::Ptr camera)
7228bf80f4bSopenharmony_ci{
7238bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(camera->entity))
7248bf80f4bSopenharmony_ci        return false;
7258bf80f4bSopenharmony_ci
7268bf80f4bSopenharmony_ci    if (auto cc = cameraComponentManager_->Write(camera->entity)) {
7278bf80f4bSopenharmony_ci        auto& em = ecs_->GetEntityManager();
7288bf80f4bSopenharmony_ci        cc->renderResolution[0] = static_cast<float>(camera->width);
7298bf80f4bSopenharmony_ci        cc->renderResolution[1] = static_cast<float>(camera->height);
7308bf80f4bSopenharmony_ci        cc->customColorTargets = { GetOrCreateEntityReference(em, *rhComponentManager_, camera->colorImage) };
7318bf80f4bSopenharmony_ci        if (camera->depthImage) {
7328bf80f4bSopenharmony_ci            cc->customDepthTarget = GetOrCreateEntityReference(em, *rhComponentManager_, camera->depthImage);
7338bf80f4bSopenharmony_ci        }
7348bf80f4bSopenharmony_ci        if (cc->sceneFlags & CameraComponent::SceneFlagBits::ACTIVE_RENDER_BIT) {
7358bf80f4bSopenharmony_ci            // please render also.
7368bf80f4bSopenharmony_ci            return true;
7378bf80f4bSopenharmony_ci        }
7388bf80f4bSopenharmony_ci    }
7398bf80f4bSopenharmony_ci    // no render.
7408bf80f4bSopenharmony_ci    return false;
7418bf80f4bSopenharmony_ci}
7428bf80f4bSopenharmony_ci
7438bf80f4bSopenharmony_civoid SceneHolder::ResetScene(bool initialize)
7448bf80f4bSopenharmony_ci{
7458bf80f4bSopenharmony_ci    bool wasScenePrepared = scenePrepared_;
7468bf80f4bSopenharmony_ci    scenePrepared_ = false;
7478bf80f4bSopenharmony_ci    if (wasScenePrepared && initialize) {
7488bf80f4bSopenharmony_ci        return;
7498bf80f4bSopenharmony_ci    }
7508bf80f4bSopenharmony_ci
7518bf80f4bSopenharmony_ci    SetMainCamera({});
7528bf80f4bSopenharmony_ci    cameras_.clear();
7538bf80f4bSopenharmony_ci
7548bf80f4bSopenharmony_ci    animations_.clear();
7558bf80f4bSopenharmony_ci
7568bf80f4bSopenharmony_ci    // Release resource data.
7578bf80f4bSopenharmony_ci    gltfResourceData_ = {};
7588bf80f4bSopenharmony_ci    sceneEntity_ = {};
7598bf80f4bSopenharmony_ci
7608bf80f4bSopenharmony_ci    // Release default camera.
7618bf80f4bSopenharmony_ci    defaultCameraEntity_ = {};
7628bf80f4bSopenharmony_ci
7638bf80f4bSopenharmony_ci    // Release scene
7648bf80f4bSopenharmony_ci    scene_ = {};
7658bf80f4bSopenharmony_ci    assetManager_ = {};
7668bf80f4bSopenharmony_ci
7678bf80f4bSopenharmony_ci    // Release scene root.
7688bf80f4bSopenharmony_ci    rootNode_ = {};
7698bf80f4bSopenharmony_ci
7708bf80f4bSopenharmony_ci    // fully recreate ECS if requested
7718bf80f4bSopenharmony_ci    if (ecs_) {
7728bf80f4bSopenharmony_ci        cameraComponentManager_ = {};
7738bf80f4bSopenharmony_ci        meshComponentManager_ = {};
7748bf80f4bSopenharmony_ci        nameComponentManager_ = {};
7758bf80f4bSopenharmony_ci        nodeComponentManager_ = {};
7768bf80f4bSopenharmony_ci        meshQuery_ = {};
7778bf80f4bSopenharmony_ci        materialQuery_ = {};
7788bf80f4bSopenharmony_ci        animationQuery_ = {};
7798bf80f4bSopenharmony_ci        ecsListener_->Reset();
7808bf80f4bSopenharmony_ci        ecs_->Uninitialize();
7818bf80f4bSopenharmony_ci        ecs_.reset();
7828bf80f4bSopenharmony_ci    }
7838bf80f4bSopenharmony_ci
7848bf80f4bSopenharmony_ci    if (sceneUninitializedCallback_) {
7858bf80f4bSopenharmony_ci        QueueApplicationTask(MakeTask(
7868bf80f4bSopenharmony_ci                                 [](auto callback) {
7878bf80f4bSopenharmony_ci                                     callback->Invoke();
7888bf80f4bSopenharmony_ci                                     return false;
7898bf80f4bSopenharmony_ci                                 },
7908bf80f4bSopenharmony_ci                                 sceneUninitializedCallback_),
7918bf80f4bSopenharmony_ci            false);
7928bf80f4bSopenharmony_ci    }
7938bf80f4bSopenharmony_ci
7948bf80f4bSopenharmony_ci    if (initialize && CreateDefaultEcs()) {
7958bf80f4bSopenharmony_ci        // Create new root node.
7968bf80f4bSopenharmony_ci        CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
7978bf80f4bSopenharmony_ci        rootNode_ = nodeSystem.CreateNode();
7988bf80f4bSopenharmony_ci        rootNode_->SetName(ROOTNODE_NAME);
7998bf80f4bSopenharmony_ci        if (nodeComponentManager_) {
8008bf80f4bSopenharmony_ci            nodeComponentManager_->Create(rootNode_->GetEntity());
8018bf80f4bSopenharmony_ci        }
8028bf80f4bSopenharmony_ci        scene_ = SCENE_NS::IEntityCollection::Ptr { new SCENE_NS::EntityCollection(*ecs_, "scene", {}) };
8038bf80f4bSopenharmony_ci
8048bf80f4bSopenharmony_ci        // it seems that having our root entity as a part of loaded entify has no significant effect on
8058bf80f4bSopenharmony_ci        // anything Presumably it is ok to keep it out of the serialization auto entityRef =
8068bf80f4bSopenharmony_ci
8078bf80f4bSopenharmony_ci        rootNode_->SetEnabled(true);
8088bf80f4bSopenharmony_ci
8098bf80f4bSopenharmony_ci        assetManager_ =
8108bf80f4bSopenharmony_ci            SCENE_NS::IAssetManager::Ptr { new SCENE_NS::AssetManager(*renderContext_, *graphicsContext3D_) };
8118bf80f4bSopenharmony_ci    }
8128bf80f4bSopenharmony_ci}
8138bf80f4bSopenharmony_ci
8148bf80f4bSopenharmony_civoid SceneHolder::SetSceneSystemGraph(const BASE_NS::string& uri)
8158bf80f4bSopenharmony_ci{
8168bf80f4bSopenharmony_ci    if (uri != sceneSystemGraphUri_) {
8178bf80f4bSopenharmony_ci        sceneSystemGraphUri_ = uri;
8188bf80f4bSopenharmony_ci        scenePrepared_ = false;
8198bf80f4bSopenharmony_ci        if (scene_) {
8208bf80f4bSopenharmony_ci            // reload with new graph
8218bf80f4bSopenharmony_ci            LoadScene();
8228bf80f4bSopenharmony_ci
8238bf80f4bSopenharmony_ci        } else if (sceneLoadedCallback_) {
8248bf80f4bSopenharmony_ci            QueueApplicationTask(MakeTask(
8258bf80f4bSopenharmony_ci                                     [](auto sceneLoadedCallback) {
8268bf80f4bSopenharmony_ci                                         if (sceneLoadedCallback) {
8278bf80f4bSopenharmony_ci                                             sceneLoadedCallback->Invoke(SCENE_NS::IScene::SCENE_STATUS_UNINITIALIZED);
8288bf80f4bSopenharmony_ci                                         }
8298bf80f4bSopenharmony_ci                                         return false;
8308bf80f4bSopenharmony_ci                                     },
8318bf80f4bSopenharmony_ci                                     sceneLoadedCallback_),
8328bf80f4bSopenharmony_ci                false);
8338bf80f4bSopenharmony_ci        }
8348bf80f4bSopenharmony_ci    }
8358bf80f4bSopenharmony_ci}
8368bf80f4bSopenharmony_ci
8378bf80f4bSopenharmony_civoid SceneHolder::LoadScene(const BASE_NS::string& uri)
8388bf80f4bSopenharmony_ci{
8398bf80f4bSopenharmony_ci    // ToDo: LoadScene shoud deal with this, but currently triggers a problem when we swap between instances
8408bf80f4bSopenharmony_ci    if (sceneUri_ == uri) {
8418bf80f4bSopenharmony_ci        if (sceneLoadedCallback_) {
8428bf80f4bSopenharmony_ci            bool haveEcs = (ecs_ == nullptr);
8438bf80f4bSopenharmony_ci            QueueApplicationTask(MakeTask(
8448bf80f4bSopenharmony_ci                                     [haveEcs](auto sceneLoadedCallback) {
8458bf80f4bSopenharmony_ci                                         if (sceneLoadedCallback) {
8468bf80f4bSopenharmony_ci                                             sceneLoadedCallback->Invoke(
8478bf80f4bSopenharmony_ci                                                 haveEcs ? SCENE_NS::IScene::SCENE_STATUS_READY
8488bf80f4bSopenharmony_ci                                                         : SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED);
8498bf80f4bSopenharmony_ci                                         }
8508bf80f4bSopenharmony_ci                                         return false;
8518bf80f4bSopenharmony_ci                                     },
8528bf80f4bSopenharmony_ci                                     sceneLoadedCallback_),
8538bf80f4bSopenharmony_ci                false);
8548bf80f4bSopenharmony_ci        }
8558bf80f4bSopenharmony_ci        return;
8568bf80f4bSopenharmony_ci    }
8578bf80f4bSopenharmony_ci    sceneUri_ = uri;
8588bf80f4bSopenharmony_ci    LoadScene();
8598bf80f4bSopenharmony_ci}
8608bf80f4bSopenharmony_ci
8618bf80f4bSopenharmony_cistatic constexpr BASE_NS::string_view KDUMMY_STRING { "!#&/dummy" };
8628bf80f4bSopenharmony_ci
8638bf80f4bSopenharmony_civoid SceneHolder::IntrospectNodeless()
8648bf80f4bSopenharmony_ci{
8658bf80f4bSopenharmony_ci#ifndef NDEBUG
8668bf80f4bSopenharmony_ci    Entity dummy {};
8678bf80f4bSopenharmony_ci    FindMesh(KDUMMY_STRING, KDUMMY_STRING, dummy);
8688bf80f4bSopenharmony_ci    FindMaterial(KDUMMY_STRING, KDUMMY_STRING, dummy);
8698bf80f4bSopenharmony_ci#endif // !NDEBUG
8708bf80f4bSopenharmony_ci
8718bf80f4bSopenharmony_ci    RemoveUriComponentsFromMeshes();
8728bf80f4bSopenharmony_ci    ResolveAnimations();
8738bf80f4bSopenharmony_ci}
8748bf80f4bSopenharmony_ci
8758bf80f4bSopenharmony_cibool GetEntityId(const CORE_NS::Entity& entity, BASE_NS::string_view& entityName,
8768bf80f4bSopenharmony_ci    SCENE_NS::IEntityCollection& collection, BASE_NS::string_view backupCollection,
8778bf80f4bSopenharmony_ci    CORE3D_NS::INameComponentManager& nameComponentManager)
8788bf80f4bSopenharmony_ci{
8798bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(entity)) {
8808bf80f4bSopenharmony_ci        entityName = collection.GetUniqueIdentifierRecursive(entity);
8818bf80f4bSopenharmony_ci        if (!entityName.empty() && entityName != "/") {
8828bf80f4bSopenharmony_ci            return true;
8838bf80f4bSopenharmony_ci        } else {
8848bf80f4bSopenharmony_ci            if (auto readHandle = nameComponentManager.Read(entity)) {
8858bf80f4bSopenharmony_ci                entityName = readHandle->name;
8868bf80f4bSopenharmony_ci                collection.AddEntityToSubcollection(backupCollection, entityName, entity, true);
8878bf80f4bSopenharmony_ci                auto gltfCollectionIx = collection.GetSubCollectionIndex(backupCollection);
8888bf80f4bSopenharmony_ci                if (auto gltfCollection = collection.GetSubCollection(gltfCollectionIx)) {
8898bf80f4bSopenharmony_ci                    entityName = gltfCollection->GetUniqueIdentifier(entity);
8908bf80f4bSopenharmony_ci                    return true;
8918bf80f4bSopenharmony_ci                }
8928bf80f4bSopenharmony_ci            } else {
8938bf80f4bSopenharmony_ci                // ToDo: we could store entity id even it did not have name component
8948bf80f4bSopenharmony_ci                CORE_LOG_W("%s: entity missing from collections", __func__);
8958bf80f4bSopenharmony_ci            }
8968bf80f4bSopenharmony_ci        }
8978bf80f4bSopenharmony_ci    }
8988bf80f4bSopenharmony_ci    return false;
8998bf80f4bSopenharmony_ci}
9008bf80f4bSopenharmony_ci
9018bf80f4bSopenharmony_civoid ExtractQueryResults(CORE_NS::ComponentQuery& query, SCENE_NS::IEntityCollection& collection,
9028bf80f4bSopenharmony_ci    BASE_NS::string_view backupCollection, BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>>& result,
9038bf80f4bSopenharmony_ci    CORE3D_NS::INameComponentManager& nameComponentManager)
9048bf80f4bSopenharmony_ci{
9058bf80f4bSopenharmony_ci    query.Execute();
9068bf80f4bSopenharmony_ci    auto results = query.GetResults();
9078bf80f4bSopenharmony_ci    for (auto& row : results) {
9088bf80f4bSopenharmony_ci        BASE_NS::string_view id;
9098bf80f4bSopenharmony_ci        if (GetEntityId(row.entity, id, collection, backupCollection, nameComponentManager)) {
9108bf80f4bSopenharmony_ci            result->push_back(id);
9118bf80f4bSopenharmony_ci        }
9128bf80f4bSopenharmony_ci    }
9138bf80f4bSopenharmony_ci}
9148bf80f4bSopenharmony_ci
9158bf80f4bSopenharmony_ciBASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> SceneHolder::ListMaterialNames()
9168bf80f4bSopenharmony_ci{
9178bf80f4bSopenharmony_ci    BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> ret { new BASE_NS::vector<BASE_NS::string_view> };
9188bf80f4bSopenharmony_ci    if (materialQuery_ && scene_) {
9198bf80f4bSopenharmony_ci        ExtractQueryResults(*materialQuery_, *scene_.get(), "GLTF_Materials", ret, *nameComponentManager_);
9208bf80f4bSopenharmony_ci    }
9218bf80f4bSopenharmony_ci    return ret;
9228bf80f4bSopenharmony_ci}
9238bf80f4bSopenharmony_ci
9248bf80f4bSopenharmony_ciBASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> SceneHolder::ListMeshNames()
9258bf80f4bSopenharmony_ci{
9268bf80f4bSopenharmony_ci    BASE_NS::shared_ptr<BASE_NS::vector<BASE_NS::string_view>> ret { new BASE_NS::vector<BASE_NS::string_view> };
9278bf80f4bSopenharmony_ci    if (meshQuery_ && scene_) {
9288bf80f4bSopenharmony_ci        ExtractQueryResults(*meshQuery_, *scene_.get(), "GLTF_Meshes", ret, *nameComponentManager_);
9298bf80f4bSopenharmony_ci    }
9308bf80f4bSopenharmony_ci    return ret;
9318bf80f4bSopenharmony_ci}
9328bf80f4bSopenharmony_ci
9338bf80f4bSopenharmony_civoid SceneHolder::RemoveUriComponentsFromMeshes()
9348bf80f4bSopenharmony_ci{
9358bf80f4bSopenharmony_ci    meshQuery_->Execute();
9368bf80f4bSopenharmony_ci    auto meshes = meshQuery_->GetResults();
9378bf80f4bSopenharmony_ci
9388bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("found %zu meshes", meshes.size());
9398bf80f4bSopenharmony_ci
9408bf80f4bSopenharmony_ci    // Remove uri component from meshes, since it causes issues with prefab loading.
9418bf80f4bSopenharmony_ci    // The gltf importer shares the meshes between collections, if they have
9428bf80f4bSopenharmony_ci    // similar uri.
9438bf80f4bSopenharmony_ci    // However, this is not desired behavior, because scene-overridden property
9448bf80f4bSopenharmony_ci    // values will propagate to future prefab instances (e.g. material).
9458bf80f4bSopenharmony_ci    for (auto& mesh : meshes) {
9468bf80f4bSopenharmony_ci        if (uriComponentManager_->HasComponent(mesh.entity)) {
9478bf80f4bSopenharmony_ci            uriComponentManager_->Destroy(mesh.entity);
9488bf80f4bSopenharmony_ci        }
9498bf80f4bSopenharmony_ci    }
9508bf80f4bSopenharmony_ci}
9518bf80f4bSopenharmony_ci
9528bf80f4bSopenharmony_cibool SceneHolder::FindMesh(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
9538bf80f4bSopenharmony_ci{
9548bf80f4bSopenharmony_ci    if (ecs_) {
9558bf80f4bSopenharmony_ci        entity = scene_->GetEntityRecursive(fullPath);
9568bf80f4bSopenharmony_ci        if (CORE_NS::EntityUtil::IsValid(entity)) {
9578bf80f4bSopenharmony_ci            return true;
9588bf80f4bSopenharmony_ci        }
9598bf80f4bSopenharmony_ci
9608bf80f4bSopenharmony_ci        meshQuery_->Execute();
9618bf80f4bSopenharmony_ci        auto meshes = meshQuery_->GetResults();
9628bf80f4bSopenharmony_ci
9638bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("found %zu meshes", meshes.size());
9648bf80f4bSopenharmony_ci
9658bf80f4bSopenharmony_ci#ifdef NDEBUG
9668bf80f4bSopenharmony_ci        if (name == KDUMMY_STRING) {
9678bf80f4bSopenharmony_ci            return false;
9688bf80f4bSopenharmony_ci        }
9698bf80f4bSopenharmony_ci#endif
9708bf80f4bSopenharmony_ci
9718bf80f4bSopenharmony_ci        for (auto&& mesh : meshes) {
9728bf80f4bSopenharmony_ci            bool effectivelyEnabled = false;
9738bf80f4bSopenharmony_ci            if (auto readHandle = nodeComponentManager_->Read(mesh.components[1])) {
9748bf80f4bSopenharmony_ci                effectivelyEnabled = readHandle->effectivelyEnabled;
9758bf80f4bSopenharmony_ci            }
9768bf80f4bSopenharmony_ci            BASE_NS::string entityName;
9778bf80f4bSopenharmony_ci            if (auto readHandle = nameComponentManager_->Read(mesh.components[2])) {
9788bf80f4bSopenharmony_ci                entityName = readHandle->name;
9798bf80f4bSopenharmony_ci            }
9808bf80f4bSopenharmony_ci            SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
9818bf80f4bSopenharmony_ci            if (name == entityName || fullPath == entityName) {
9828bf80f4bSopenharmony_ci                entity = mesh.entity;
9838bf80f4bSopenharmony_ci                return true;
9848bf80f4bSopenharmony_ci            }
9858bf80f4bSopenharmony_ci        }
9868bf80f4bSopenharmony_ci        // Could not find the mesh with given the name, try if it has a node
9878bf80f4bSopenharmony_ci        const auto& root = nodeSystem_->GetRootNode();
9888bf80f4bSopenharmony_ci        if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
9898bf80f4bSopenharmony_ci            entity = ecsNode->GetEntity();
9908bf80f4bSopenharmony_ci            return true;
9918bf80f4bSopenharmony_ci        }
9928bf80f4bSopenharmony_ci    }
9938bf80f4bSopenharmony_ci    return false;
9948bf80f4bSopenharmony_ci}
9958bf80f4bSopenharmony_ci
9968bf80f4bSopenharmony_ciBASE_NS::string SceneHolder::GetResourceId(CORE_NS::Entity entity)
9978bf80f4bSopenharmony_ci{
9988bf80f4bSopenharmony_ci    BASE_NS::string result;
9998bf80f4bSopenharmony_ci
10008bf80f4bSopenharmony_ci    if (scene_) {
10018bf80f4bSopenharmony_ci        result = scene_->GetUniqueIdentifierRecursive(entity);
10028bf80f4bSopenharmony_ci    }
10038bf80f4bSopenharmony_ci    return result;
10048bf80f4bSopenharmony_ci}
10058bf80f4bSopenharmony_ci
10068bf80f4bSopenharmony_cibool SceneHolder::FindMaterial(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
10078bf80f4bSopenharmony_ci{
10088bf80f4bSopenharmony_ci    if (ecs_) {
10098bf80f4bSopenharmony_ci        entity = scene_->GetEntityRecursive(fullPath);
10108bf80f4bSopenharmony_ci        if (CORE_NS::EntityUtil::IsValid(entity)) {
10118bf80f4bSopenharmony_ci            return true;
10128bf80f4bSopenharmony_ci        }
10138bf80f4bSopenharmony_ci
10148bf80f4bSopenharmony_ci        materialQuery_->Execute();
10158bf80f4bSopenharmony_ci        auto materials = materialQuery_->GetResults();
10168bf80f4bSopenharmony_ci
10178bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("found %zu materials", materials.size());
10188bf80f4bSopenharmony_ci
10198bf80f4bSopenharmony_ci#ifdef NDEBUG
10208bf80f4bSopenharmony_ci        if (name == KDUMMY_STRING) {
10218bf80f4bSopenharmony_ci            return false;
10228bf80f4bSopenharmony_ci        }
10238bf80f4bSopenharmony_ci#endif
10248bf80f4bSopenharmony_ci
10258bf80f4bSopenharmony_ci        for (auto&& material : materials) {
10268bf80f4bSopenharmony_ci            bool effectivelyEnabled = false;
10278bf80f4bSopenharmony_ci            if (auto readHandle = nodeComponentManager_->Read(material.components[1])) {
10288bf80f4bSopenharmony_ci                effectivelyEnabled = readHandle->effectivelyEnabled;
10298bf80f4bSopenharmony_ci            }
10308bf80f4bSopenharmony_ci            BASE_NS::string entityName;
10318bf80f4bSopenharmony_ci            if (auto readHandle = nameComponentManager_->Read(material.components[2])) {
10328bf80f4bSopenharmony_ci                entityName = readHandle->name;
10338bf80f4bSopenharmony_ci            }
10348bf80f4bSopenharmony_ci            SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
10358bf80f4bSopenharmony_ci            if (name == entityName) {
10368bf80f4bSopenharmony_ci                entity = material.entity;
10378bf80f4bSopenharmony_ci                return true;
10388bf80f4bSopenharmony_ci            }
10398bf80f4bSopenharmony_ci            if (auto readHandle = uriComponentManager_->Read(material.components[3])) {
10408bf80f4bSopenharmony_ci                entityName = readHandle->uri;
10418bf80f4bSopenharmony_ci            }
10428bf80f4bSopenharmony_ci
10438bf80f4bSopenharmony_ci            if (!entityName.empty()) {
10448bf80f4bSopenharmony_ci                if (name == entityName || fullPath == entityName) {
10458bf80f4bSopenharmony_ci                    entity = material.entity;
10468bf80f4bSopenharmony_ci                    return true;
10478bf80f4bSopenharmony_ci                }
10488bf80f4bSopenharmony_ci            }
10498bf80f4bSopenharmony_ci        }
10508bf80f4bSopenharmony_ci        // Could not find the material with the given name, try if it has a node
10518bf80f4bSopenharmony_ci        const auto& root = nodeSystem_->GetRootNode();
10528bf80f4bSopenharmony_ci        if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
10538bf80f4bSopenharmony_ci            entity = ecsNode->GetEntity();
10548bf80f4bSopenharmony_ci            return true;
10558bf80f4bSopenharmony_ci        }
10568bf80f4bSopenharmony_ci        // Desperate measures, to be rectified
10578bf80f4bSopenharmony_ci        if (auto created = rootNode_->LookupNodeByPath(fullPath)) {
10588bf80f4bSopenharmony_ci            entity = created->GetEntity();
10598bf80f4bSopenharmony_ci            return true;
10608bf80f4bSopenharmony_ci        }
10618bf80f4bSopenharmony_ci    }
10628bf80f4bSopenharmony_ci    return false;
10638bf80f4bSopenharmony_ci}
10648bf80f4bSopenharmony_ci
10658bf80f4bSopenharmony_cibool SceneHolder::FindAnimation(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
10668bf80f4bSopenharmony_ci{
10678bf80f4bSopenharmony_ci    if (ecs_) {
10688bf80f4bSopenharmony_ci        if (!animations_.empty()) {
10698bf80f4bSopenharmony_ci            size_t ix = name.rfind(":");
10708bf80f4bSopenharmony_ci            if (ix != BASE_NS::string_view::npos && ix != name.size() - 1) {
10718bf80f4bSopenharmony_ci                char* dummy = nullptr;
10728bf80f4bSopenharmony_ci                auto entityId = strtoll(name.substr(ix + 1).data(), &dummy, 16);
10738bf80f4bSopenharmony_ci                if (animations_.find(entityId) != animations_.cend()) {
10748bf80f4bSopenharmony_ci                    entity.id = entityId;
10758bf80f4bSopenharmony_ci                    return true;
10768bf80f4bSopenharmony_ci                }
10778bf80f4bSopenharmony_ci            }
10788bf80f4bSopenharmony_ci
10798bf80f4bSopenharmony_ci            for (auto&& animation : animations_) {
10808bf80f4bSopenharmony_ci                if (META_NS::GetValue(interface_pointer_cast<META_NS::INamed>(animation.second)->Name()) == name) {
10818bf80f4bSopenharmony_ci                    entity.id = animation.first;
10828bf80f4bSopenharmony_ci                    return true;
10838bf80f4bSopenharmony_ci                }
10848bf80f4bSopenharmony_ci            }
10858bf80f4bSopenharmony_ci        } else {
10868bf80f4bSopenharmony_ci            animationQuery_->Execute();
10878bf80f4bSopenharmony_ci            auto animations = animationQuery_->GetResults();
10888bf80f4bSopenharmony_ci
10898bf80f4bSopenharmony_ci            SCENE_PLUGIN_VERBOSE_LOG("found %zu animations", animations.size());
10908bf80f4bSopenharmony_ci
10918bf80f4bSopenharmony_ci#ifdef NDEBUG
10928bf80f4bSopenharmony_ci            if (name == KDUMMY_STRING) {
10938bf80f4bSopenharmony_ci                return false;
10948bf80f4bSopenharmony_ci            }
10958bf80f4bSopenharmony_ci#endif
10968bf80f4bSopenharmony_ci
10978bf80f4bSopenharmony_ci            for (auto&& animation : animations) {
10988bf80f4bSopenharmony_ci                bool effectivelyEnabled = false;
10998bf80f4bSopenharmony_ci                if (auto readHandle = nodeComponentManager_->Read(animation.components[1])) {
11008bf80f4bSopenharmony_ci                    effectivelyEnabled = readHandle->effectivelyEnabled;
11018bf80f4bSopenharmony_ci                }
11028bf80f4bSopenharmony_ci                BASE_NS::string entityName;
11038bf80f4bSopenharmony_ci                if (auto readHandle = nameComponentManager_->Read(animation.components[2])) {
11048bf80f4bSopenharmony_ci                    entityName = readHandle->name;
11058bf80f4bSopenharmony_ci                }
11068bf80f4bSopenharmony_ci                SCENE_PLUGIN_VERBOSE_LOG("name: %s enabled: %i", entityName.c_str(), effectivelyEnabled);
11078bf80f4bSopenharmony_ci                if (name == entityName || fullPath == entityName) {
11088bf80f4bSopenharmony_ci                    entity = animation.entity;
11098bf80f4bSopenharmony_ci                    return true;
11108bf80f4bSopenharmony_ci                }
11118bf80f4bSopenharmony_ci            }
11128bf80f4bSopenharmony_ci            // Could not find the animation with given the name, try if it has a node
11138bf80f4bSopenharmony_ci            const auto& root = nodeSystem_->GetRootNode();
11148bf80f4bSopenharmony_ci            if (auto ecsNode = root.LookupNodeByPath(fullPath)) {
11158bf80f4bSopenharmony_ci                entity = ecsNode->GetEntity();
11168bf80f4bSopenharmony_ci                return true;
11178bf80f4bSopenharmony_ci            }
11188bf80f4bSopenharmony_ci        }
11198bf80f4bSopenharmony_ci    }
11208bf80f4bSopenharmony_ci    return false;
11218bf80f4bSopenharmony_ci}
11228bf80f4bSopenharmony_ci
11238bf80f4bSopenharmony_civoid SceneHolder::ResolveAnimations()
11248bf80f4bSopenharmony_ci{
11258bf80f4bSopenharmony_ci    if (ecs_) {
11268bf80f4bSopenharmony_ci        animationQuery_->Execute();
11278bf80f4bSopenharmony_ci        auto animations = animationQuery_->GetResults();
11288bf80f4bSopenharmony_ci
11298bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("%s, found %zu animations", __func__, animations.size());
11308bf80f4bSopenharmony_ci
11318bf80f4bSopenharmony_ci        for (auto&& animation : animations) {
11328bf80f4bSopenharmony_ci            if (animations_.find(animation.entity.id) == animations_.cend()) {
11338bf80f4bSopenharmony_ci                animations_[animation.entity.id] =
11348bf80f4bSopenharmony_ci                    GetObjectRegistry().Create<SCENE_NS::IEcsAnimation>(SCENE_NS::ClassId::EcsAnimation);
11358bf80f4bSopenharmony_ci                if (auto ecsProxyIf =
11368bf80f4bSopenharmony_ci                        interface_pointer_cast<SCENE_NS::IEcsProxyObject>(animations_[animation.entity.id])) {
11378bf80f4bSopenharmony_ci                    ecsProxyIf->SetCommonListener(GetCommonEcsListener());
11388bf80f4bSopenharmony_ci                }
11398bf80f4bSopenharmony_ci                animations_[animation.entity.id]->SetEntity(*ecs_, animation.entity);
11408bf80f4bSopenharmony_ci            }
11418bf80f4bSopenharmony_ci        }
11428bf80f4bSopenharmony_ci    }
11438bf80f4bSopenharmony_ci}
11448bf80f4bSopenharmony_ci
11458bf80f4bSopenharmony_civoid SceneHolder::UpdateAttachments(SCENE_NS::IEcsObject::Ptr& ecsObject)
11468bf80f4bSopenharmony_ci{
11478bf80f4bSopenharmony_ci    if (ecs_) {
11488bf80f4bSopenharmony_ci        auto entity = ecsObject->GetEntity();
11498bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
11508bf80f4bSopenharmony_ci            for (auto&& animation : animations_) {
11518bf80f4bSopenharmony_ci                if (animation.second->GetRootEntity() == entity) {
11528bf80f4bSopenharmony_ci                    ecsObject->AddAttachment(animation.second->GetEntity());
11538bf80f4bSopenharmony_ci                }
11548bf80f4bSopenharmony_ci            }
11558bf80f4bSopenharmony_ci        }
11568bf80f4bSopenharmony_ci    }
11578bf80f4bSopenharmony_ci}
11588bf80f4bSopenharmony_ci
11598bf80f4bSopenharmony_ci// This could be highly inefficient, in most cases we should have a clue of resource type
11608bf80f4bSopenharmony_cibool SceneHolder::FindResource(const BASE_NS::string_view name, const BASE_NS::string_view fullPath, Entity& entity)
11618bf80f4bSopenharmony_ci{
11628bf80f4bSopenharmony_ci    if (ecs_ && scene_) {
11638bf80f4bSopenharmony_ci        if (FindAnimation(name, fullPath, entity) || FindMaterial(name, fullPath, entity) ||
11648bf80f4bSopenharmony_ci            FindMesh(name, fullPath, entity)) {
11658bf80f4bSopenharmony_ci            return true;
11668bf80f4bSopenharmony_ci        }
11678bf80f4bSopenharmony_ci
11688bf80f4bSopenharmony_ci        // traverse through scene collection
11698bf80f4bSopenharmony_ci        for (size_t ix = 0; ix < scene_->GetSubCollectionCount(); ix++) {
11708bf80f4bSopenharmony_ci            if (const auto& subcollection = scene_->GetSubCollection(ix); subcollection->GetUri() == fullPath) {
11718bf80f4bSopenharmony_ci                // the assumption is that we do not have to dig deeper
11728bf80f4bSopenharmony_ci                if (subcollection->GetEntityCount() > 0) {
11738bf80f4bSopenharmony_ci                    entity = subcollection->GetEntity(0);
11748bf80f4bSopenharmony_ci                    return true;
11758bf80f4bSopenharmony_ci                }
11768bf80f4bSopenharmony_ci            }
11778bf80f4bSopenharmony_ci        }
11788bf80f4bSopenharmony_ci
11798bf80f4bSopenharmony_ci        // Try finding an existing resource with an uri. This is needed e.g. for the images loaded from an glTF
11808bf80f4bSopenharmony_ci        // file where the uri does not point to an actual image file but the resource is just a entity with uri in
11818bf80f4bSopenharmony_ci        // ECS.
11828bf80f4bSopenharmony_ci        if (renderMeshComponentManager_ && uriComponentManager_) {
11838bf80f4bSopenharmony_ci            for (size_t i = 0; i < uriComponentManager_->GetComponentCount(); ++i) {
11848bf80f4bSopenharmony_ci                const Entity currentEntity =
11858bf80f4bSopenharmony_ci                    uriComponentManager_->GetEntity(static_cast<IComponentManager::ComponentId>(i));
11868bf80f4bSopenharmony_ci                if (ecs_->GetEntityManager().IsAlive(currentEntity)) {
11878bf80f4bSopenharmony_ci                    if (auto uriComponent = uriComponentManager_->Read(currentEntity);
11888bf80f4bSopenharmony_ci                        uriComponent && uriComponent->uri == fullPath) {
11898bf80f4bSopenharmony_ci                        if (renderMeshComponentManager_->HasComponent(currentEntity)) {
11908bf80f4bSopenharmony_ci                            entity = currentEntity;
11918bf80f4bSopenharmony_ci                            return true;
11928bf80f4bSopenharmony_ci                        }
11938bf80f4bSopenharmony_ci                    }
11948bf80f4bSopenharmony_ci                }
11958bf80f4bSopenharmony_ci            }
11968bf80f4bSopenharmony_ci        }
11978bf80f4bSopenharmony_ci    }
11988bf80f4bSopenharmony_ci
11998bf80f4bSopenharmony_ci    return false;
12008bf80f4bSopenharmony_ci}
12018bf80f4bSopenharmony_ci
12028bf80f4bSopenharmony_cibool SceneHolder::GetImageEntity(CORE_NS::Entity material, size_t index, CORE_NS::Entity& entity)
12038bf80f4bSopenharmony_ci{
12048bf80f4bSopenharmony_ci    bool ret { false };
12058bf80f4bSopenharmony_ci    if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(material)) {
12068bf80f4bSopenharmony_ci        if (auto handle = materialComponentManager_->Read(material)) {
12078bf80f4bSopenharmony_ci            entity = handle->textures[index].image;
12088bf80f4bSopenharmony_ci            ret = true;
12098bf80f4bSopenharmony_ci        }
12108bf80f4bSopenharmony_ci    }
12118bf80f4bSopenharmony_ci
12128bf80f4bSopenharmony_ci    return ret;
12138bf80f4bSopenharmony_ci}
12148bf80f4bSopenharmony_ci
12158bf80f4bSopenharmony_cibool SceneHolder::GetRenderHandleUri(const RENDER_NS::RenderHandle& handle, BASE_NS::string& uriString)
12168bf80f4bSopenharmony_ci{
12178bf80f4bSopenharmony_ci    if (ecs_) {
12188bf80f4bSopenharmony_ci        auto& renderUtil = graphicsContext3D_->GetRenderContext().GetRenderUtil();
12198bf80f4bSopenharmony_ci
12208bf80f4bSopenharmony_ci        size_t index { 0 };
12218bf80f4bSopenharmony_ci        while (auto handleReference = rhComponentManager_->GetRenderHandleReference(index)) {
12228bf80f4bSopenharmony_ci            if (handleReference.GetHandle() == handle) {
12238bf80f4bSopenharmony_ci                auto& renderUtil = graphicsContext3D_->GetRenderContext().GetRenderUtil();
12248bf80f4bSopenharmony_ci                const auto desc = renderUtil.GetRenderHandleDesc(handleReference);
12258bf80f4bSopenharmony_ci                if (desc.type == RenderHandleType::GPU_IMAGE && !desc.name.empty()) {
12268bf80f4bSopenharmony_ci                    // Note: assuming that the name is the image uri. Ignore the name if not in uri format.
12278bf80f4bSopenharmony_ci                    if (desc.name.find(":/") != BASE_NS::string::npos) {
12288bf80f4bSopenharmony_ci                        uriString = desc.name;
12298bf80f4bSopenharmony_ci                        return true;
12308bf80f4bSopenharmony_ci                    }
12318bf80f4bSopenharmony_ci                }
12328bf80f4bSopenharmony_ci            }
12338bf80f4bSopenharmony_ci            index++;
12348bf80f4bSopenharmony_ci        }
12358bf80f4bSopenharmony_ci    }
12368bf80f4bSopenharmony_ci    return false;
12378bf80f4bSopenharmony_ci}
12388bf80f4bSopenharmony_ci
12398bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreatePostProcess()
12408bf80f4bSopenharmony_ci{
12418bf80f4bSopenharmony_ci    CORE_NS::Entity entity;
12428bf80f4bSopenharmony_ci    if (ecs_) {
12438bf80f4bSopenharmony_ci        auto pm = CORE_NS::GetManager<CORE3D_NS::IPostProcessComponentManager>(*ecs_);
12448bf80f4bSopenharmony_ci        entity = ecs_->GetEntityManager().Create();
12458bf80f4bSopenharmony_ci        // createComponent
12468bf80f4bSopenharmony_ci        pm->Create(entity);
12478bf80f4bSopenharmony_ci    }
12488bf80f4bSopenharmony_ci    return entity;
12498bf80f4bSopenharmony_ci}
12508bf80f4bSopenharmony_ci
12518bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateRenderConfiguration()
12528bf80f4bSopenharmony_ci{
12538bf80f4bSopenharmony_ci    CORE_NS::Entity entity;
12548bf80f4bSopenharmony_ci    if (ecs_) {
12558bf80f4bSopenharmony_ci        entity = ecs_->GetEntityManager().Create();
12568bf80f4bSopenharmony_ci
12578bf80f4bSopenharmony_ci        auto rcm = CORE_NS::GetManager<CORE3D_NS::IRenderConfigurationComponentManager>(*ecs_);
12588bf80f4bSopenharmony_ci        rcm->Create(entity);
12598bf80f4bSopenharmony_ci    }
12608bf80f4bSopenharmony_ci    return entity;
12618bf80f4bSopenharmony_ci}
12628bf80f4bSopenharmony_ci
12638bf80f4bSopenharmony_civoid SceneHolder::SetRenderHandle(const CORE_NS::Entity& target, const CORE_NS::Entity& source)
12648bf80f4bSopenharmony_ci{
12658bf80f4bSopenharmony_ci    if (ecs_) {
12668bf80f4bSopenharmony_ci        if (auto sourceHandle = rhComponentManager_->GetRenderHandleReference(source)) {
12678bf80f4bSopenharmony_ci            if (!rhComponentManager_->HasComponent(target)) {
12688bf80f4bSopenharmony_ci                rhComponentManager_->Create(target);
12698bf80f4bSopenharmony_ci            }
12708bf80f4bSopenharmony_ci            if (auto handle = rhComponentManager_->Write(target)) {
12718bf80f4bSopenharmony_ci                handle->reference = sourceHandle;
12728bf80f4bSopenharmony_ci            }
12738bf80f4bSopenharmony_ci        }
12748bf80f4bSopenharmony_ci    }
12758bf80f4bSopenharmony_ci}
12768bf80f4bSopenharmony_ci
12778bf80f4bSopenharmony_cibool SceneHolder::GetEntityUri(const CORE_NS::Entity& entity, BASE_NS::string& uriString)
12788bf80f4bSopenharmony_ci{
12798bf80f4bSopenharmony_ci    bool ret { false };
12808bf80f4bSopenharmony_ci    if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
12818bf80f4bSopenharmony_ci        if (auto handle = uriComponentManager_->Read(entity)) {
12828bf80f4bSopenharmony_ci            uriString = BASE_NS::string(handle->uri.data(), handle->uri.size());
12838bf80f4bSopenharmony_ci            ret = true;
12848bf80f4bSopenharmony_ci        }
12858bf80f4bSopenharmony_ci    }
12868bf80f4bSopenharmony_ci
12878bf80f4bSopenharmony_ci    if (!ret) {
12888bf80f4bSopenharmony_ci        // Special handling for render handles (automatically loaded images in the ecs are now just render handles
12898bf80f4bSopenharmony_ci        // with a name containing the uri).
12908bf80f4bSopenharmony_ci        auto handle = rhComponentManager_->GetRenderHandleReference(entity);
12918bf80f4bSopenharmony_ci        if (handle) {
12928bf80f4bSopenharmony_ci            auto& renderUtil = renderContext_->GetRenderUtil();
12938bf80f4bSopenharmony_ci            const auto desc = renderUtil.GetRenderHandleDesc(handle);
12948bf80f4bSopenharmony_ci            if (desc.type == RenderHandleType::GPU_IMAGE && !desc.name.empty()) {
12958bf80f4bSopenharmony_ci                // Note: assuming that the name is the image uri. Ignore the name if not in uri format.
12968bf80f4bSopenharmony_ci                if (desc.name.find(":/") != BASE_NS::string::npos) {
12978bf80f4bSopenharmony_ci                    uriString = desc.name;
12988bf80f4bSopenharmony_ci                    ret = true;
12998bf80f4bSopenharmony_ci                }
13008bf80f4bSopenharmony_ci            }
13018bf80f4bSopenharmony_ci        }
13028bf80f4bSopenharmony_ci    }
13038bf80f4bSopenharmony_ci
13048bf80f4bSopenharmony_ci    return ret;
13058bf80f4bSopenharmony_ci}
13068bf80f4bSopenharmony_cibool SceneHolder::GetImageHandle(
13078bf80f4bSopenharmony_ci    const CORE_NS::Entity& entity, RENDER_NS::RenderHandleReference& handle, RENDER_NS::GpuImageDesc& desc)
13088bf80f4bSopenharmony_ci{
13098bf80f4bSopenharmony_ci    if (rhComponentManager_->HasComponent(entity)) {
13108bf80f4bSopenharmony_ci        handle = rhComponentManager_->GetRenderHandleReference(entity);
13118bf80f4bSopenharmony_ci        desc = renderContext_->GetDevice().GetGpuResourceManager().GetImageDescriptor(handle);
13128bf80f4bSopenharmony_ci        return true;
13138bf80f4bSopenharmony_ci    }
13148bf80f4bSopenharmony_ci    return false;
13158bf80f4bSopenharmony_ci}
13168bf80f4bSopenharmony_ci
13178bf80f4bSopenharmony_cibool SceneHolder::SetEntityUri(const CORE_NS::Entity& entity, const BASE_NS::string& uriString)
13188bf80f4bSopenharmony_ci{
13198bf80f4bSopenharmony_ci    bool ret { false };
13208bf80f4bSopenharmony_ci    if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
13218bf80f4bSopenharmony_ci        if (!uriComponentManager_->HasComponent(entity)) {
13228bf80f4bSopenharmony_ci            uriComponentManager_->Create(entity);
13238bf80f4bSopenharmony_ci        }
13248bf80f4bSopenharmony_ci
13258bf80f4bSopenharmony_ci        if (auto handle = uriComponentManager_->Write(entity)) {
13268bf80f4bSopenharmony_ci            handle->uri = uriString;
13278bf80f4bSopenharmony_ci            ret = true;
13288bf80f4bSopenharmony_ci        }
13298bf80f4bSopenharmony_ci    }
13308bf80f4bSopenharmony_ci
13318bf80f4bSopenharmony_ci    return ret;
13328bf80f4bSopenharmony_ci}
13338bf80f4bSopenharmony_ci
13348bf80f4bSopenharmony_cibool SceneHolder::GetEntityName(const CORE_NS::Entity& entity, BASE_NS::string& nameString)
13358bf80f4bSopenharmony_ci{
13368bf80f4bSopenharmony_ci    bool ret { false };
13378bf80f4bSopenharmony_ci    if (ecs_ && scene_ && CORE_NS::EntityUtil::IsValid(entity)) {
13388bf80f4bSopenharmony_ci        if (auto handle = nameComponentManager_->Read(entity)) {
13398bf80f4bSopenharmony_ci            nameString = BASE_NS::string(handle->name.data(), handle->name.size());
13408bf80f4bSopenharmony_ci            ret = true;
13418bf80f4bSopenharmony_ci        }
13428bf80f4bSopenharmony_ci    }
13438bf80f4bSopenharmony_ci
13448bf80f4bSopenharmony_ci    return ret;
13458bf80f4bSopenharmony_ci}
13468bf80f4bSopenharmony_ci
13478bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::GetEntityByUri(BASE_NS::string_view uriString)
13488bf80f4bSopenharmony_ci{
13498bf80f4bSopenharmony_ci    for (size_t i = 0; i < uriComponentManager_->GetComponentCount(); ++i) {
13508bf80f4bSopenharmony_ci        const Entity entity = uriComponentManager_->GetEntity(static_cast<IComponentManager::ComponentId>(i));
13518bf80f4bSopenharmony_ci        if (ecs_->GetEntityManager().IsAlive(entity)) {
13528bf80f4bSopenharmony_ci            if (auto uriComponent = uriComponentManager_->Read(entity);
13538bf80f4bSopenharmony_ci                uriComponent && uriComponent->uri == uriString) {
13548bf80f4bSopenharmony_ci                return entity;
13558bf80f4bSopenharmony_ci            }
13568bf80f4bSopenharmony_ci        }
13578bf80f4bSopenharmony_ci    }
13588bf80f4bSopenharmony_ci
13598bf80f4bSopenharmony_ci    return {};
13608bf80f4bSopenharmony_ci}
13618bf80f4bSopenharmony_ci
13628bf80f4bSopenharmony_cibool ResolveNodeFullPath(CORE3D_NS::ISceneNode* node, BASE_NS::string& path)
13638bf80f4bSopenharmony_ci{
13648bf80f4bSopenharmony_ci    if (node) {
13658bf80f4bSopenharmony_ci        path = node->GetName();
13668bf80f4bSopenharmony_ci        while ((node = node->GetParent())) {
13678bf80f4bSopenharmony_ci            path.insert(0, "/");
13688bf80f4bSopenharmony_ci            auto name = node->GetName();
13698bf80f4bSopenharmony_ci            path.insert(0, name.data(), name.size());
13708bf80f4bSopenharmony_ci        }
13718bf80f4bSopenharmony_ci    }
13728bf80f4bSopenharmony_ci    return (!path.empty());
13738bf80f4bSopenharmony_ci}
13748bf80f4bSopenharmony_ci
13758bf80f4bSopenharmony_ciBASE_NS::string ResolveNodeFullPath(CORE_NS::IEcs& ecs, const CORE_NS::Entity& entity)
13768bf80f4bSopenharmony_ci{
13778bf80f4bSopenharmony_ci    CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(ecs);
13788bf80f4bSopenharmony_ci    BASE_NS::string ret;
13798bf80f4bSopenharmony_ci    ResolveNodeFullPath(nodeSystem.GetNode(entity), ret);
13808bf80f4bSopenharmony_ci    return ret;
13818bf80f4bSopenharmony_ci}
13828bf80f4bSopenharmony_ci
13838bf80f4bSopenharmony_civoid SceneHolder::LoadScene()
13848bf80f4bSopenharmony_ci{
13858bf80f4bSopenharmony_ci    // Reset scene to default.
13868bf80f4bSopenharmony_ci    CORE_LOG_I("Loading scene: '%s'", sceneUri_.c_str());
13878bf80f4bSopenharmony_ci    uint32_t loadingStatus = SCENE_NS::IScene::SCENE_STATUS_LOADING_FAILED;
13888bf80f4bSopenharmony_ci    bool replacedRoot { false };
13898bf80f4bSopenharmony_ci
13908bf80f4bSopenharmony_ci    while (true) {
13918bf80f4bSopenharmony_ci        if (sceneUri_.empty()) {
13928bf80f4bSopenharmony_ci            ResetScene();
13938bf80f4bSopenharmony_ci            loadingStatus = SCENE_NS::IScene::SCENE_STATUS_UNINITIALIZED;
13948bf80f4bSopenharmony_ci            break;
13958bf80f4bSopenharmony_ci        }
13968bf80f4bSopenharmony_ci
13978bf80f4bSopenharmony_ci        auto params = SCENE_NS::PathUtil::GetUriParameters(sceneUri_);
13988bf80f4bSopenharmony_ci        auto ite = params.find("target");
13998bf80f4bSopenharmony_ci        if (!scene_ || ite == params.end() || ite->second.empty()) {
14008bf80f4bSopenharmony_ci            ResetScene(true);
14018bf80f4bSopenharmony_ci            replacedRoot = true;
14028bf80f4bSopenharmony_ci        } else {
14038bf80f4bSopenharmony_ci            CORE_LOG_I("Load into scene: %s", ite->second.c_str());
14048bf80f4bSopenharmony_ci        }
14058bf80f4bSopenharmony_ci
14068bf80f4bSopenharmony_ci        // If ecs initializing failed, report it back and return
14078bf80f4bSopenharmony_ci        if (!ecs_) {
14088bf80f4bSopenharmony_ci            break;
14098bf80f4bSopenharmony_ci        }
14108bf80f4bSopenharmony_ci
14118bf80f4bSopenharmony_ci        if (assetManager_) {
14128bf80f4bSopenharmony_ci            if ((sceneUri_ != "scene://empty") && !assetManager_->LoadAsset(*scene_, sceneUri_, "project://")) {
14138bf80f4bSopenharmony_ci                CORE_LOG_E("Loading scene %s failed", sceneUri_.c_str());
14148bf80f4bSopenharmony_ci                ResetScene();
14158bf80f4bSopenharmony_ci                break;
14168bf80f4bSopenharmony_ci            } else { // ToDo: This is currently done also when a node is added to container, so no need to do it
14178bf80f4bSopenharmony_ci                     // here
14188bf80f4bSopenharmony_ci                // Rearrange scene to have a concrete common root node, this will be more important for prefabs
14198bf80f4bSopenharmony_ci                CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
14208bf80f4bSopenharmony_ci                auto& root = nodeSystem.GetRootNode();
14218bf80f4bSopenharmony_ci
14228bf80f4bSopenharmony_ci                // ToDo: should this fetch the named root node instead
14238bf80f4bSopenharmony_ci                auto ourRoot = root.GetChildren().at(0);
14248bf80f4bSopenharmony_ci                ourRoot->SetEnabled(true);
14258bf80f4bSopenharmony_ci
14268bf80f4bSopenharmony_ci                auto ite = root.GetChildren().begin() + 1;
14278bf80f4bSopenharmony_ci                while (ite != root.GetChildren().end()) {
14288bf80f4bSopenharmony_ci                    (*ite)->SetParent(*ourRoot);
14298bf80f4bSopenharmony_ci                    ite = root.GetChildren().begin() + 1;
14308bf80f4bSopenharmony_ci                }
14318bf80f4bSopenharmony_ci            }
14328bf80f4bSopenharmony_ci
14338bf80f4bSopenharmony_ci            // Loading might have cached some assets (in case there are multiple
14348bf80f4bSopenharmony_ci            // instances). Scene widget will not need them after loading so clear the
14358bf80f4bSopenharmony_ci            // cache.
14368bf80f4bSopenharmony_ci            if (replacedRoot) {
14378bf80f4bSopenharmony_ci                assetManager_->ClearCache();
14388bf80f4bSopenharmony_ci            }
14398bf80f4bSopenharmony_ci        }
14408bf80f4bSopenharmony_ci        if (sceneUri_ != "scene://empty") {
14418bf80f4bSopenharmony_ci            // Set default camera.
14428bf80f4bSopenharmony_ci            SetDefaultCamera();
14438bf80f4bSopenharmony_ci        }
14448bf80f4bSopenharmony_ci        // ask synchronous update
14458bf80f4bSopenharmony_ci        RenderCameras();
14468bf80f4bSopenharmony_ci        loadingStatus = SCENE_NS::IScene::SCENE_STATUS_READY;
14478bf80f4bSopenharmony_ci        break;
14488bf80f4bSopenharmony_ci    }
14498bf80f4bSopenharmony_ci
14508bf80f4bSopenharmony_ci    // If ecs initialization fails, all we can do is to retry loading later
14518bf80f4bSopenharmony_ci    if (!ecs_) {
14528bf80f4bSopenharmony_ci        loadSceneFailed_ = true;
14538bf80f4bSopenharmony_ci
14548bf80f4bSopenharmony_ci        if (sceneLoadedCallback_) {
14558bf80f4bSopenharmony_ci            QueueApplicationTask(MakeTask(
14568bf80f4bSopenharmony_ci                                     [](auto sceneLoadedCallback, auto loadingStatus) {
14578bf80f4bSopenharmony_ci                                         if (sceneLoadedCallback)
14588bf80f4bSopenharmony_ci                                             sceneLoadedCallback->Invoke(loadingStatus);
14598bf80f4bSopenharmony_ci                                         return false;
14608bf80f4bSopenharmony_ci                                     },
14618bf80f4bSopenharmony_ci                                     sceneLoadedCallback_, loadingStatus),
14628bf80f4bSopenharmony_ci                false);
14638bf80f4bSopenharmony_ci        }
14648bf80f4bSopenharmony_ci        return;
14658bf80f4bSopenharmony_ci    }
14668bf80f4bSopenharmony_ci
14678bf80f4bSopenharmony_ci    // make sure that components get updated
14688bf80f4bSopenharmony_ci    ProcessEvents();
14698bf80f4bSopenharmony_ci
14708bf80f4bSopenharmony_ci    IntrospectNodeless();
14718bf80f4bSopenharmony_ci    // Call back the app thread, notify that the graphics and ecs are ready. This
14728bf80f4bSopenharmony_ci    // is not quite true, though
14738bf80f4bSopenharmony_ci    if (ecs_ && replacedRoot && sceneInitializedCallback_) {
14748bf80f4bSopenharmony_ci        BASE_NS::string id { rootNode_->GetName() };
14758bf80f4bSopenharmony_ci        BASE_NS::string cameraId = ResolveNodeFullPath(*ecs_, defaultCameraEntity_);
14768bf80f4bSopenharmony_ci        QueueApplicationTask(MakeTask(
14778bf80f4bSopenharmony_ci                                 [](auto sceneInitializedCallback, auto id, auto cameraId) {
14788bf80f4bSopenharmony_ci                                     if (sceneInitializedCallback) {
14798bf80f4bSopenharmony_ci                                         sceneInitializedCallback->Invoke(id, cameraId);
14808bf80f4bSopenharmony_ci                                     }
14818bf80f4bSopenharmony_ci                                     return false;
14828bf80f4bSopenharmony_ci                                 },
14838bf80f4bSopenharmony_ci                                 sceneInitializedCallback_, id, cameraId),
14848bf80f4bSopenharmony_ci            false);
14858bf80f4bSopenharmony_ci    } else if (sceneLoadedCallback_) { // Call back the app thread, notify that new scene is loaded
14868bf80f4bSopenharmony_ci        QueueApplicationTask(MakeTask(
14878bf80f4bSopenharmony_ci                                 [](auto sceneLoadedCallback, auto loadingStatus) {
14888bf80f4bSopenharmony_ci                                     if (sceneLoadedCallback) {
14898bf80f4bSopenharmony_ci                                         sceneLoadedCallback->Invoke(loadingStatus);
14908bf80f4bSopenharmony_ci                                     }
14918bf80f4bSopenharmony_ci                                     return false;
14928bf80f4bSopenharmony_ci                                 },
14938bf80f4bSopenharmony_ci                                 sceneLoadedCallback_, loadingStatus),
14948bf80f4bSopenharmony_ci            false);
14958bf80f4bSopenharmony_ci    }
14968bf80f4bSopenharmony_ci}
14978bf80f4bSopenharmony_ci
14988bf80f4bSopenharmony_civoid SceneHolder::ChangeCamera(SCENE_NS::ICamera::Ptr camera)
14998bf80f4bSopenharmony_ci{
15008bf80f4bSopenharmony_ci    if (auto cameraObject = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) {
15018bf80f4bSopenharmony_ci        auto entity = cameraObject->GetEntity();
15028bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
15038bf80f4bSopenharmony_ci            SetMainCamera(entity);
15048bf80f4bSopenharmony_ci        }
15058bf80f4bSopenharmony_ci    }
15068bf80f4bSopenharmony_ci}
15078bf80f4bSopenharmony_ci
15088bf80f4bSopenharmony_civoid logNodes(const CORE3D_NS::ISceneNode& node, BASE_NS::string path)
15098bf80f4bSopenharmony_ci{
15108bf80f4bSopenharmony_ci    if (!path.empty() && path.back() != '/') {
15118bf80f4bSopenharmony_ci        path.append("/");
15128bf80f4bSopenharmony_ci    }
15138bf80f4bSopenharmony_ci    if (!node.GetName().empty()) {
15148bf80f4bSopenharmony_ci        path.append(node.GetName());
15158bf80f4bSopenharmony_ci    } else {
15168bf80f4bSopenharmony_ci        path.append("[");
15178bf80f4bSopenharmony_ci        path.append(BASE_NS::to_string(node.GetEntity().id));
15188bf80f4bSopenharmony_ci        path.append("]");
15198bf80f4bSopenharmony_ci    }
15208bf80f4bSopenharmony_ci    CORE_LOG_I("%s", path.c_str());
15218bf80f4bSopenharmony_ci
15228bf80f4bSopenharmony_ci    for (const auto child : node.GetChildren())
15238bf80f4bSopenharmony_ci        logNodes(*child, path);
15248bf80f4bSopenharmony_ci}
15258bf80f4bSopenharmony_ci
15268bf80f4bSopenharmony_civoid SceneHolder::SaveScene(const BASE_NS::string& fileName)
15278bf80f4bSopenharmony_ci{
15288bf80f4bSopenharmony_ci    assetManager_->SaveJsonEntityCollection(*scene_.get(), fileName.empty() ? sceneUri_ : fileName, "file://");
15298bf80f4bSopenharmony_ci
15308bf80f4bSopenharmony_ci    // Verbose logs, to be suppressed at some point
15318bf80f4bSopenharmony_ci    CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
15328bf80f4bSopenharmony_ci    logNodes(nodeSystem.GetRootNode(), "/");
15338bf80f4bSopenharmony_ci    IntrospectNodeless();
15348bf80f4bSopenharmony_ci}
15358bf80f4bSopenharmony_ci
15368bf80f4bSopenharmony_ciCORE3D_NS::ISceneNode* SceneHolder::CreateNode(const BASE_NS::string& name)
15378bf80f4bSopenharmony_ci{
15388bf80f4bSopenharmony_ci    return CreateNode({}, name);
15398bf80f4bSopenharmony_ci}
15408bf80f4bSopenharmony_ci
15418bf80f4bSopenharmony_ciCORE3D_NS::ISceneNode* SceneHolder::CreateNode(const BASE_NS::string& path, const BASE_NS::string& name)
15428bf80f4bSopenharmony_ci{
15438bf80f4bSopenharmony_ci    if (ecs_) {
15448bf80f4bSopenharmony_ci        auto pathWithoutRootNode = RemoveRootNodeFromPath(path);
15458bf80f4bSopenharmony_ci
15468bf80f4bSopenharmony_ci        CORE3D_NS::INodeSystem& nodeSystem = *GetSystem<CORE3D_NS::INodeSystem>(*ecs_);
15478bf80f4bSopenharmony_ci
15488bf80f4bSopenharmony_ci        CORE3D_NS::ISceneNode* parent = nullptr;
15498bf80f4bSopenharmony_ci        if (pathWithoutRootNode.empty()) {
15508bf80f4bSopenharmony_ci            parent = rootNode_;
15518bf80f4bSopenharmony_ci        } else {
15528bf80f4bSopenharmony_ci            parent = rootNode_->LookupNodeByPath(pathWithoutRootNode);
15538bf80f4bSopenharmony_ci        }
15548bf80f4bSopenharmony_ci
15558bf80f4bSopenharmony_ci        CORE_ASSERT(parent);
15568bf80f4bSopenharmony_ci
15578bf80f4bSopenharmony_ci        auto instanceRoot = nodeSystem.CreateNode();
15588bf80f4bSopenharmony_ci        instanceRoot->SetName(name);
15598bf80f4bSopenharmony_ci        instanceRoot->SetParent(*parent);
15608bf80f4bSopenharmony_ci        return instanceRoot;
15618bf80f4bSopenharmony_ci    } else {
15628bf80f4bSopenharmony_ci        CORE_LOG_E("%s: Ecs not available, can not create node %s", __func__, name.c_str());
15638bf80f4bSopenharmony_ci    }
15648bf80f4bSopenharmony_ci
15658bf80f4bSopenharmony_ci    return nullptr;
15668bf80f4bSopenharmony_ci}
15678bf80f4bSopenharmony_ci
15688bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateMaterial(const BASE_NS::string& name)
15698bf80f4bSopenharmony_ci{
15708bf80f4bSopenharmony_ci    if (ecs_) {
15718bf80f4bSopenharmony_ci        auto entity = ecs_->GetEntityManager().Create();
15728bf80f4bSopenharmony_ci
15738bf80f4bSopenharmony_ci        RenameEntity(entity, name);
15748bf80f4bSopenharmony_ci
15758bf80f4bSopenharmony_ci        materialComponentManager_->Create(entity);
15768bf80f4bSopenharmony_ci        scene_->AddEntityToSubcollection("created_materials", name, entity);
15778bf80f4bSopenharmony_ci        ProcessEvents();
15788bf80f4bSopenharmony_ci        return entity;
15798bf80f4bSopenharmony_ci
15808bf80f4bSopenharmony_ci    } else {
15818bf80f4bSopenharmony_ci        CORE_LOG_E("%s: Ecs not available, can not create material %s", __func__, name.c_str());
15828bf80f4bSopenharmony_ci    }
15838bf80f4bSopenharmony_ci
15848bf80f4bSopenharmony_ci    return {};
15858bf80f4bSopenharmony_ci}
15868bf80f4bSopenharmony_ci
15878bf80f4bSopenharmony_civoid SceneHolder::RenameEntity(CORE_NS::Entity entity, const BASE_NS::string& name)
15888bf80f4bSopenharmony_ci{
15898bf80f4bSopenharmony_ci    if (ecs_) {
15908bf80f4bSopenharmony_ci        // Name Component
15918bf80f4bSopenharmony_ci        if (!nameComponentManager_->HasComponent(entity)) {
15928bf80f4bSopenharmony_ci            nameComponentManager_->Create(entity);
15938bf80f4bSopenharmony_ci        }
15948bf80f4bSopenharmony_ci        if (auto nameHandle = nameComponentManager_->Write(entity)) {
15958bf80f4bSopenharmony_ci            nameHandle->name = name;
15968bf80f4bSopenharmony_ci        }
15978bf80f4bSopenharmony_ci
15988bf80f4bSopenharmony_ci        // Root level entity collection item
15998bf80f4bSopenharmony_ci        if (BASE_NS::string_view prevName = scene_->GetUniqueIdentifier(entity); !prevName.empty()) {
16008bf80f4bSopenharmony_ci            scene_->SetUniqueIdentifier(name, scene_->GetEntity(prevName));
16018bf80f4bSopenharmony_ci        } else if (nodeComponentManager_->HasComponent(entity)) {
16028bf80f4bSopenharmony_ci            if (auto ecsNode = nodeSystem_->GetNode(entity)) {
16038bf80f4bSopenharmony_ci                if (const auto& children = ecsNode->GetChildren(); children.size()) {
16048bf80f4bSopenharmony_ci                    if (auto ix = scene_->GetSubCollectionIndexByRoot(children[0]->GetEntity()); ix != -1) {
16058bf80f4bSopenharmony_ci                        scene_->GetSubCollection(ix)->SetUri(name);
16068bf80f4bSopenharmony_ci                    }
16078bf80f4bSopenharmony_ci                }
16088bf80f4bSopenharmony_ci            }
16098bf80f4bSopenharmony_ci        }
16108bf80f4bSopenharmony_ci        // Experimentals: Subcollection root (will not traverse further, the rest should go through normal property
16118bf80f4bSopenharmony_ci        // serialization)
16128bf80f4bSopenharmony_ci    }
16138bf80f4bSopenharmony_ci}
16148bf80f4bSopenharmony_ci
16158bf80f4bSopenharmony_ci// Clone the entity, reference will be stored
16168bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CloneEntity(CORE_NS::Entity entity, const BASE_NS::string& name, bool storeWithUniqueId)
16178bf80f4bSopenharmony_ci{
16188bf80f4bSopenharmony_ci    CORE_NS::Entity ret {};
16198bf80f4bSopenharmony_ci
16208bf80f4bSopenharmony_ci    if (ecs_ && scene_) {
16218bf80f4bSopenharmony_ci        ret = ecs_->GetEntityManager().Create();
16228bf80f4bSopenharmony_ci        CORE_NS::CloneComponents(*ecs_, entity, *ecs_, ret);
16238bf80f4bSopenharmony_ci        RenameEntity(ret, name);
16248bf80f4bSopenharmony_ci        // when cloning, we trust that implementation uses unique name so no padding required
16258bf80f4bSopenharmony_ci        scene_->AddEntityToSubcollection("cloned_entities", name, ret, storeWithUniqueId);
16268bf80f4bSopenharmony_ci    }
16278bf80f4bSopenharmony_ci    return ret;
16288bf80f4bSopenharmony_ci}
16298bf80f4bSopenharmony_ci
16308bf80f4bSopenharmony_civoid SceneHolder::DestroyEntity(CORE_NS::Entity entity)
16318bf80f4bSopenharmony_ci{
16328bf80f4bSopenharmony_ci    // Destroy created materials & meshes here.
16338bf80f4bSopenharmony_ci    auto meshCollectionIndex = scene_->GetSubCollectionIndex("GLTF_Meshes");
16348bf80f4bSopenharmony_ci    if (meshCollectionIndex != -1) {
16358bf80f4bSopenharmony_ci        auto meshCollection = scene_->GetSubCollection(meshCollectionIndex);
16368bf80f4bSopenharmony_ci        if (meshCollection->Contains(entity)) {
16378bf80f4bSopenharmony_ci            auto ref = meshCollection->GetReference(entity);
16388bf80f4bSopenharmony_ci            meshCollection->RemoveEntity(ref);
16398bf80f4bSopenharmony_ci        }
16408bf80f4bSopenharmony_ci    }
16418bf80f4bSopenharmony_ci
16428bf80f4bSopenharmony_ci    auto materialCollectionIndex = scene_->GetSubCollectionIndex("GLTF_Materials");
16438bf80f4bSopenharmony_ci    if (materialCollectionIndex != -1) {
16448bf80f4bSopenharmony_ci        auto materialCollection = scene_->GetSubCollection(materialCollectionIndex);
16458bf80f4bSopenharmony_ci        if (materialCollection->Contains(entity)) {
16468bf80f4bSopenharmony_ci            auto ref = materialCollection->GetReference(entity);
16478bf80f4bSopenharmony_ci            materialCollection->RemoveEntity(ref);
16488bf80f4bSopenharmony_ci        }
16498bf80f4bSopenharmony_ci    }
16508bf80f4bSopenharmony_ci    scene_->RemoveEntityRecursive(entity);
16518bf80f4bSopenharmony_ci}
16528bf80f4bSopenharmony_ci
16538bf80f4bSopenharmony_civoid SceneHolder::SetEntityActive(CORE_NS::Entity entity, bool active)
16548bf80f4bSopenharmony_ci{
16558bf80f4bSopenharmony_ci    ecs_->GetEntityManager().SetActive(entity, active);
16568bf80f4bSopenharmony_ci}
16578bf80f4bSopenharmony_ci
16588bf80f4bSopenharmony_cibool SceneHolder::ReparentEntity(CORE_NS::Entity entity, const BASE_NS::string& parentPath, size_t index)
16598bf80f4bSopenharmony_ci{
16608bf80f4bSopenharmony_ci    auto& root = nodeSystem_->GetRootNode();
16618bf80f4bSopenharmony_ci
16628bf80f4bSopenharmony_ci    auto node = nodeSystem_->GetNode(entity);
16638bf80f4bSopenharmony_ci    if (!node) {
16648bf80f4bSopenharmony_ci        CORE_LOG_W("SceneHolder::ReparentEntity, Failed to find node from entity.");
16658bf80f4bSopenharmony_ci        return false;
16668bf80f4bSopenharmony_ci    }
16678bf80f4bSopenharmony_ci
16688bf80f4bSopenharmony_ci    auto parentNode = root.LookupNodeByPath(parentPath);
16698bf80f4bSopenharmony_ci    if (!parentNode) {
16708bf80f4bSopenharmony_ci        if (parentPath == "/" || parentPath.empty()) {
16718bf80f4bSopenharmony_ci            parentNode = &root;
16728bf80f4bSopenharmony_ci        } else {
16738bf80f4bSopenharmony_ci            CORE_LOG_W("SceneHolder::ReparentEntity, Failed to find parent node '%s'", parentPath.c_str());
16748bf80f4bSopenharmony_ci            return false;
16758bf80f4bSopenharmony_ci        }
16768bf80f4bSopenharmony_ci    }
16778bf80f4bSopenharmony_ci
16788bf80f4bSopenharmony_ci    if (parentNode != node->GetParent()) {
16798bf80f4bSopenharmony_ci        if (index != SIZE_MAX) {
16808bf80f4bSopenharmony_ci            parentNode->InsertChild(index, *node);
16818bf80f4bSopenharmony_ci        } else {
16828bf80f4bSopenharmony_ci            parentNode->AddChild(*node);
16838bf80f4bSopenharmony_ci        }
16848bf80f4bSopenharmony_ci    }
16858bf80f4bSopenharmony_ci
16868bf80f4bSopenharmony_ci    return true;
16878bf80f4bSopenharmony_ci}
16888bf80f4bSopenharmony_ci
16898bf80f4bSopenharmony_ciconst CORE3D_NS::ISceneNode* SceneHolder::ReparentEntity(const BASE_NS::string& parentPath, const BASE_NS::string& name)
16908bf80f4bSopenharmony_ci{
16918bf80f4bSopenharmony_ci    if (ecs_) {
16928bf80f4bSopenharmony_ci        const auto& root = nodeSystem_->GetRootNode();
16938bf80f4bSopenharmony_ci        auto ecsNode = root.LookupNodeByPath(name);
16948bf80f4bSopenharmony_ci        auto parentNode = root.LookupNodeByPath(parentPath);
16958bf80f4bSopenharmony_ci
16968bf80f4bSopenharmony_ci        if (!ecsNode && parentNode) {
16978bf80f4bSopenharmony_ci            if (ecsNode = parentNode->LookupNodeByPath(name); !ecsNode) {
16988bf80f4bSopenharmony_ci                CORE_LOG_W("Could not find: '%s', tried root and parent '%s'", name.c_str(), parentPath.c_str());
16998bf80f4bSopenharmony_ci            }
17008bf80f4bSopenharmony_ci        } else if (parentNode && parentNode != ecsNode) { // prefabs may get have their path pointing them self
17018bf80f4bSopenharmony_ci                                                          // before they are positioned into scene
17028bf80f4bSopenharmony_ci            const_cast<CORE3D_NS::ISceneNode*>(ecsNode)->SetParent(*parentNode);
17038bf80f4bSopenharmony_ci            SCENE_PLUGIN_VERBOSE_LOG("reparenting '%s' to '%s'", name.c_str(), parentPath.c_str());
17048bf80f4bSopenharmony_ci        } else if (!parentPath.empty() && parentPath != "/") {
17058bf80f4bSopenharmony_ci            CORE_LOG_W("Could not find parent '%s'", parentPath.c_str());
17068bf80f4bSopenharmony_ci            // Even parent is not found, we can still activate the bindings, still we could
17078bf80f4bSopenharmony_ci            // reschedule retry here
17088bf80f4bSopenharmony_ci        }
17098bf80f4bSopenharmony_ci        return ecsNode;
17108bf80f4bSopenharmony_ci    }
17118bf80f4bSopenharmony_ci    return {};
17128bf80f4bSopenharmony_ci}
17138bf80f4bSopenharmony_ci
17148bf80f4bSopenharmony_civoid SceneHolder::SetMesh(CORE_NS::Entity targetEntity, CORE_NS::Entity mesh)
17158bf80f4bSopenharmony_ci{
17168bf80f4bSopenharmony_ci    if (ecs_) {
17178bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity) && EntityUtil::IsValid(mesh)) {
17188bf80f4bSopenharmony_ci            // ToDo: should perhaps generate render mesh component for entity if it does not exist yet?
17198bf80f4bSopenharmony_ci
17208bf80f4bSopenharmony_ci            if (!renderMeshComponentManager_->HasComponent(targetEntity)) {
17218bf80f4bSopenharmony_ci                renderMeshComponentManager_->Create(targetEntity);
17228bf80f4bSopenharmony_ci            }
17238bf80f4bSopenharmony_ci
17248bf80f4bSopenharmony_ci            if (auto handle = renderMeshComponentManager_->Write(targetEntity)) {
17258bf80f4bSopenharmony_ci                handle->mesh = mesh;
17268bf80f4bSopenharmony_ci            }
17278bf80f4bSopenharmony_ci        }
17288bf80f4bSopenharmony_ci    }
17298bf80f4bSopenharmony_ci}
17308bf80f4bSopenharmony_ci
17318bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::GetMaterial(CORE_NS::Entity meshEntity, int64_t submeshIndex)
17328bf80f4bSopenharmony_ci{
17338bf80f4bSopenharmony_ci    CORE_NS::Entity material;
17348bf80f4bSopenharmony_ci    if (ecs_) {
17358bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(meshEntity)) {
17368bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Read(meshEntity)) {
17378bf80f4bSopenharmony_ci                if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
17388bf80f4bSopenharmony_ci                    material = handle->submeshes[submeshIndex].material;
17398bf80f4bSopenharmony_ci                }
17408bf80f4bSopenharmony_ci            }
17418bf80f4bSopenharmony_ci        }
17428bf80f4bSopenharmony_ci    }
17438bf80f4bSopenharmony_ci    return material;
17448bf80f4bSopenharmony_ci}
17458bf80f4bSopenharmony_ci
17468bf80f4bSopenharmony_ciBASE_NS::string_view SceneHolder::GetMaterialName(CORE_NS::Entity meshEntity, int64_t submeshIndex)
17478bf80f4bSopenharmony_ci{
17488bf80f4bSopenharmony_ci    BASE_NS::string_view entityName;
17498bf80f4bSopenharmony_ci    auto entity = GetMaterial(meshEntity, submeshIndex);
17508bf80f4bSopenharmony_ci
17518bf80f4bSopenharmony_ci    if (!GetEntityId(entity, entityName, *scene_.get(), "GLTF_Materials", *nameComponentManager_)) {
17528bf80f4bSopenharmony_ci        CORE_LOG_W("%s: could not find material", __func__);
17538bf80f4bSopenharmony_ci    }
17548bf80f4bSopenharmony_ci
17558bf80f4bSopenharmony_ci    return entityName;
17568bf80f4bSopenharmony_ci}
17578bf80f4bSopenharmony_ci
17588bf80f4bSopenharmony_ciBASE_NS::string_view SceneHolder::GetMeshName(CORE_NS::Entity referringEntity)
17598bf80f4bSopenharmony_ci{
17608bf80f4bSopenharmony_ci    BASE_NS::string_view entityName;
17618bf80f4bSopenharmony_ci
17628bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(referringEntity)) {
17638bf80f4bSopenharmony_ci        CORE_NS::Entity meshEntity;
17648bf80f4bSopenharmony_ci
17658bf80f4bSopenharmony_ci        if (renderMeshComponentManager_->HasComponent(referringEntity)) {
17668bf80f4bSopenharmony_ci            if (auto handle = renderMeshComponentManager_->Read(referringEntity)) {
17678bf80f4bSopenharmony_ci                meshEntity = handle->mesh;
17688bf80f4bSopenharmony_ci            }
17698bf80f4bSopenharmony_ci        } else {
17708bf80f4bSopenharmony_ci            CORE_LOG_W("%s: could not find mesh from entity", __func__);
17718bf80f4bSopenharmony_ci        }
17728bf80f4bSopenharmony_ci        if (!GetEntityId(meshEntity, entityName, *scene_.get(), "GLTF_Meshes", *nameComponentManager_)) {
17738bf80f4bSopenharmony_ci            CORE_LOG_W("%s: could not find valid mesh", __func__);
17748bf80f4bSopenharmony_ci        }
17758bf80f4bSopenharmony_ci    }
17768bf80f4bSopenharmony_ci    return entityName;
17778bf80f4bSopenharmony_ci}
17788bf80f4bSopenharmony_ci
17798bf80f4bSopenharmony_civoid SceneHolder::SetMaterial(CORE_NS::Entity targetEntity, CORE_NS::Entity material, int64_t submeshIndex)
17808bf80f4bSopenharmony_ci{
17818bf80f4bSopenharmony_ci    if (ecs_) {
17828bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
17838bf80f4bSopenharmony_ci            // ToDo: should perhaps generate mesh component for entity if it does not exist yet?
17848bf80f4bSopenharmony_ci
17858bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Write(targetEntity)) {
17868bf80f4bSopenharmony_ci                if (submeshIndex == -1) {
17878bf80f4bSopenharmony_ci                    for (auto&& submesh : handle->submeshes) {
17888bf80f4bSopenharmony_ci                        submesh.material = material;
17898bf80f4bSopenharmony_ci                    }
17908bf80f4bSopenharmony_ci                } else if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
17918bf80f4bSopenharmony_ci                    handle->submeshes[submeshIndex].material = material;
17928bf80f4bSopenharmony_ci                }
17938bf80f4bSopenharmony_ci            }
17948bf80f4bSopenharmony_ci        }
17958bf80f4bSopenharmony_ci    }
17968bf80f4bSopenharmony_ci}
17978bf80f4bSopenharmony_ci
17988bf80f4bSopenharmony_ciCORE_NS::EntityReference SceneHolder::BindUIBitmap(SCENE_NS::IBitmap::Ptr bitmap, bool createNew)
17998bf80f4bSopenharmony_ci{
18008bf80f4bSopenharmony_ci    if (ecs_) {
18018bf80f4bSopenharmony_ci        BASE_NS::string uri;
18028bf80f4bSopenharmony_ci        RENDER_NS::RenderHandleReference imageHandle {};
18038bf80f4bSopenharmony_ci
18048bf80f4bSopenharmony_ci        // Need two things, uri
18058bf80f4bSopenharmony_ci        if (auto uriBmp = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap)) {
18068bf80f4bSopenharmony_ci            uri = uriBmp->Uri()->GetValue();
18078bf80f4bSopenharmony_ci        } else {
18088bf80f4bSopenharmony_ci            uri = interface_pointer_cast<META_NS::IObjectInstance>(bitmap)->GetInstanceId().ToString();
18098bf80f4bSopenharmony_ci        }
18108bf80f4bSopenharmony_ci
18118bf80f4bSopenharmony_ci        // And concrete handle to data
18128bf80f4bSopenharmony_ci        if (auto lumeBmp = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap)) {
18138bf80f4bSopenharmony_ci            imageHandle = lumeBmp->GetRenderHandle();
18148bf80f4bSopenharmony_ci        }
18158bf80f4bSopenharmony_ci
18168bf80f4bSopenharmony_ci        if (imageHandle) {
18178bf80f4bSopenharmony_ci            // check if we have existing resource
18188bf80f4bSopenharmony_ci            CORE_NS::Entity existing;
18198bf80f4bSopenharmony_ci            if (FindResource(uri, uri, existing)) {
18208bf80f4bSopenharmony_ci                auto hande = rhComponentManager_->Get(existing);
18218bf80f4bSopenharmony_ci                hande.reference = imageHandle;
18228bf80f4bSopenharmony_ci                rhComponentManager_->Set(existing, hande);
18238bf80f4bSopenharmony_ci
18248bf80f4bSopenharmony_ci                return ecs_->GetEntityManager().GetReferenceCounted(existing);
18258bf80f4bSopenharmony_ci            }
18268bf80f4bSopenharmony_ci
18278bf80f4bSopenharmony_ci            if (!createNew) {
18288bf80f4bSopenharmony_ci                return {};
18298bf80f4bSopenharmony_ci            }
18308bf80f4bSopenharmony_ci
18318bf80f4bSopenharmony_ci            // if not, create new one
18328bf80f4bSopenharmony_ci            EntityReference entity = ecs_->GetEntityManager().CreateReferenceCounted();
18338bf80f4bSopenharmony_ci
18348bf80f4bSopenharmony_ci            nameComponentManager_->Create(entity);
18358bf80f4bSopenharmony_ci            auto component = nameComponentManager_->Get(entity);
18368bf80f4bSopenharmony_ci            component.name = uri;
18378bf80f4bSopenharmony_ci            nameComponentManager_->Set(entity, component);
18388bf80f4bSopenharmony_ci
18398bf80f4bSopenharmony_ci            // Not sure if we should do this, somehow we need to keep the entity alive
18408bf80f4bSopenharmony_ci            // with proper uri it could be found afterwards
18418bf80f4bSopenharmony_ci            auto& subcollection = scene_->AddSubCollection(uri, "bitmap://");
18428bf80f4bSopenharmony_ci            subcollection.AddEntity(entity);
18438bf80f4bSopenharmony_ci
18448bf80f4bSopenharmony_ci            // Or this. We should perhaps use URI component more
18458bf80f4bSopenharmony_ci            rhComponentManager_->Create(entity);
18468bf80f4bSopenharmony_ci            auto hande = rhComponentManager_->Get(entity);
18478bf80f4bSopenharmony_ci            hande.reference = imageHandle;
18488bf80f4bSopenharmony_ci            rhComponentManager_->Set(entity, hande);
18498bf80f4bSopenharmony_ci            return entity;
18508bf80f4bSopenharmony_ci        }
18518bf80f4bSopenharmony_ci    }
18528bf80f4bSopenharmony_ci
18538bf80f4bSopenharmony_ci    return {};
18548bf80f4bSopenharmony_ci}
18558bf80f4bSopenharmony_ci
18568bf80f4bSopenharmony_civoid SceneHolder::SetTexture(size_t index, CORE_NS::Entity targetEntity, CORE_NS::EntityReference imageEntity)
18578bf80f4bSopenharmony_ci{
18588bf80f4bSopenharmony_ci    if (ecs_) {
18598bf80f4bSopenharmony_ci        if (auto handle = materialComponentManager_->Write(targetEntity)) {
18608bf80f4bSopenharmony_ci            handle->textures[index].image = imageEntity;
18618bf80f4bSopenharmony_ci        }
18628bf80f4bSopenharmony_ci    }
18638bf80f4bSopenharmony_ci}
18648bf80f4bSopenharmony_ci
18658bf80f4bSopenharmony_ciBASE_NS::string_view ResolveSamplerUri(SCENE_NS::ITextureInfo::SamplerId samplerId)
18668bf80f4bSopenharmony_ci{
18678bf80f4bSopenharmony_ci    switch (samplerId) {
18688bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_NEAREST_REPEAT:
18698bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_NEAREST_REPEAT";
18708bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP:
18718bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_NEAREST_CLAMP";
18728bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_REPEAT:
18738bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_LINEAR_REPEAT";
18748bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP:
18758bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_LINEAR_CLAMP";
18768bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT:
18778bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_REPEAT";
18788bf80f4bSopenharmony_ci        case SCENE_NS::ITextureInfo::CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP:
18798bf80f4bSopenharmony_ci            return "engine://CORE_DEFAULT_SAMPLER_LINEAR_MIPMAP_CLAMP";
18808bf80f4bSopenharmony_ci        default:
18818bf80f4bSopenharmony_ci            CORE_LOG_W("%s: unable to find sampler uri for: %d", __func__, samplerId);
18828bf80f4bSopenharmony_ci    }
18838bf80f4bSopenharmony_ci
18848bf80f4bSopenharmony_ci    return "";
18858bf80f4bSopenharmony_ci}
18868bf80f4bSopenharmony_ci
18878bf80f4bSopenharmony_cistatic constexpr size_t ENGINE_URI_PREFIX_LEN = BASE_NS::string_view("engine://").size();
18888bf80f4bSopenharmony_ci
18898bf80f4bSopenharmony_ciSCENE_NS::IShader::Ptr SceneHolder::GetShader(CORE_NS::Entity materialEntity, ShaderType type)
18908bf80f4bSopenharmony_ci{
18918bf80f4bSopenharmony_ci    // Resolve render handle from material.
18928bf80f4bSopenharmony_ci    if (!ecs_) {
18938bf80f4bSopenharmony_ci        return {};
18948bf80f4bSopenharmony_ci    }
18958bf80f4bSopenharmony_ci
18968bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
18978bf80f4bSopenharmony_ci        return {};
18988bf80f4bSopenharmony_ci    }
18998bf80f4bSopenharmony_ci
19008bf80f4bSopenharmony_ci    RENDER_NS::RenderHandleReference shaderHandleRef;
19018bf80f4bSopenharmony_ci
19028bf80f4bSopenharmony_ci    EntityReference shaderEntityRef {};
19038bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
19048bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
19058bf80f4bSopenharmony_ci            shaderEntityRef = readHandle->materialShader.shader;
19068bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
19078bf80f4bSopenharmony_ci            shaderEntityRef = readHandle->depthShader.shader;
19088bf80f4bSopenharmony_ci        }
19098bf80f4bSopenharmony_ci    }
19108bf80f4bSopenharmony_ci
19118bf80f4bSopenharmony_ci    if (shaderEntityRef) {
19128bf80f4bSopenharmony_ci        auto rh = rhComponentManager_->GetRenderHandleReference(shaderEntityRef);
19138bf80f4bSopenharmony_ci        if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
19148bf80f4bSopenharmony_ci            auto uri = GetHandleUri(rh, HANDLE_TYPE_SHADER);
19158bf80f4bSopenharmony_ci            if (!uri.empty()) {
19168bf80f4bSopenharmony_ci                auto shader = SCENE_NS::Shader();
19178bf80f4bSopenharmony_ci
19188bf80f4bSopenharmony_ci                auto shaderInterface = interface_pointer_cast<SCENE_NS::IShader>(shader);
19198bf80f4bSopenharmony_ci                SetValue(shaderInterface->Uri(), uri);
19208bf80f4bSopenharmony_ci
19218bf80f4bSopenharmony_ci                return shader;
19228bf80f4bSopenharmony_ci            }
19238bf80f4bSopenharmony_ci        }
19248bf80f4bSopenharmony_ci    }
19258bf80f4bSopenharmony_ci
19268bf80f4bSopenharmony_ci    return {};
19278bf80f4bSopenharmony_ci}
19288bf80f4bSopenharmony_ci
19298bf80f4bSopenharmony_ciSCENE_NS::IGraphicsState::Ptr SceneHolder::GetGraphicsState(CORE_NS::Entity materialEntity, ShaderType type)
19308bf80f4bSopenharmony_ci{
19318bf80f4bSopenharmony_ci    // Resolve render handle from material.
19328bf80f4bSopenharmony_ci    if (!ecs_) {
19338bf80f4bSopenharmony_ci        return {};
19348bf80f4bSopenharmony_ci    }
19358bf80f4bSopenharmony_ci
19368bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
19378bf80f4bSopenharmony_ci        return {};
19388bf80f4bSopenharmony_ci    }
19398bf80f4bSopenharmony_ci
19408bf80f4bSopenharmony_ci    RENDER_NS::RenderHandleReference shaderHandleRef;
19418bf80f4bSopenharmony_ci
19428bf80f4bSopenharmony_ci    EntityReference stateEntityRef {};
19438bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
19448bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
19458bf80f4bSopenharmony_ci            stateEntityRef = readHandle->materialShader.graphicsState;
19468bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
19478bf80f4bSopenharmony_ci            stateEntityRef = readHandle->depthShader.graphicsState;
19488bf80f4bSopenharmony_ci        }
19498bf80f4bSopenharmony_ci    }
19508bf80f4bSopenharmony_ci
19518bf80f4bSopenharmony_ci    if (stateEntityRef) {
19528bf80f4bSopenharmony_ci        auto rh = rhComponentManager_->GetRenderHandleReference(stateEntityRef);
19538bf80f4bSopenharmony_ci        if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
19548bf80f4bSopenharmony_ci            auto uri = GetHandleUri(rh);
19558bf80f4bSopenharmony_ci            if (!uri.empty()) {
19568bf80f4bSopenharmony_ci                auto state = SCENE_NS::GraphicsState();
19578bf80f4bSopenharmony_ci
19588bf80f4bSopenharmony_ci                auto interface = interface_pointer_cast<SCENE_NS::IGraphicsState>(state);
19598bf80f4bSopenharmony_ci
19608bf80f4bSopenharmony_ci                // The uri contains either .shader or .shadergs.
19618bf80f4bSopenharmony_ci                BASE_NS::string extension = ".shadergs";
19628bf80f4bSopenharmony_ci                if (uri.find(extension) == BASE_NS::string::npos) {
19638bf80f4bSopenharmony_ci                    extension = ".shader";
19648bf80f4bSopenharmony_ci                }
19658bf80f4bSopenharmony_ci
19668bf80f4bSopenharmony_ci                // Split the uri to uri and variant.
19678bf80f4bSopenharmony_ci                auto ix = uri.find_last_of(extension);
19688bf80f4bSopenharmony_ci                if (ix != BASE_NS::string_view::npos && ix < uri.size() - 1) {
19698bf80f4bSopenharmony_ci                    SetValue(interface->Uri(), BASE_NS::string(uri.substr(0, ix + 1)));
19708bf80f4bSopenharmony_ci                    SetValue(interface->Variant(), BASE_NS::string(uri.substr(ix + 1)));
19718bf80f4bSopenharmony_ci                    SCENE_PLUGIN_VERBOSE_LOG("Got graphics state: %s variant: %s",
19728bf80f4bSopenharmony_ci                        META_NS::GetValue(interface->Uri()).c_str(), META_NS::GetValue(interface->Variant()).c_str());
19738bf80f4bSopenharmony_ci                } else {
19748bf80f4bSopenharmony_ci                    SetValue(interface->Uri(), uri);
19758bf80f4bSopenharmony_ci                    SetValue(interface->Variant(), "");
19768bf80f4bSopenharmony_ci                }
19778bf80f4bSopenharmony_ci
19788bf80f4bSopenharmony_ci                if (auto shRef = interface_cast<ISceneHolderRef>(state)) {
19798bf80f4bSopenharmony_ci                    shRef->SetSceneHolder(me_);
19808bf80f4bSopenharmony_ci                    shRef->SetIndex(type);
19818bf80f4bSopenharmony_ci                }
19828bf80f4bSopenharmony_ci
19838bf80f4bSopenharmony_ci                return state;
19848bf80f4bSopenharmony_ci            }
19858bf80f4bSopenharmony_ci        }
19868bf80f4bSopenharmony_ci    }
19878bf80f4bSopenharmony_ci
19888bf80f4bSopenharmony_ci    return {};
19898bf80f4bSopenharmony_ci}
19908bf80f4bSopenharmony_ci
19918bf80f4bSopenharmony_civoid SceneHolder::SetGraphicsState(
19928bf80f4bSopenharmony_ci    CORE_NS::Entity materialEntity, ShaderType type, const RENDER_NS::GraphicsState& state)
19938bf80f4bSopenharmony_ci{
19948bf80f4bSopenharmony_ci    if (!ecs_) {
19958bf80f4bSopenharmony_ci        return;
19968bf80f4bSopenharmony_ci    }
19978bf80f4bSopenharmony_ci
19988bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
19998bf80f4bSopenharmony_ci        return;
20008bf80f4bSopenharmony_ci    }
20018bf80f4bSopenharmony_ci
20028bf80f4bSopenharmony_ci    CORE_NS::EntityReference entityRef;
20038bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
20048bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
20058bf80f4bSopenharmony_ci            entityRef = readHandle->materialShader.graphicsState;
20068bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
20078bf80f4bSopenharmony_ci            entityRef = readHandle->depthShader.graphicsState;
20088bf80f4bSopenharmony_ci        }
20098bf80f4bSopenharmony_ci    }
20108bf80f4bSopenharmony_ci
20118bf80f4bSopenharmony_ci    auto rh = rhComponentManager_->GetRenderHandleReference(entityRef);
20128bf80f4bSopenharmony_ci    if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
20138bf80f4bSopenharmony_ci        auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
20148bf80f4bSopenharmony_ci        auto hash = engineShaderManager.HashGraphicsState(state);
20158bf80f4bSopenharmony_ci        auto currentState = engineShaderManager.GetGraphicsState(rh);
20168bf80f4bSopenharmony_ci        if (hash != engineShaderManager.HashGraphicsState(currentState)) {
20178bf80f4bSopenharmony_ci            auto desc = engineShaderManager.GetIdDesc(rh);
20188bf80f4bSopenharmony_ci            engineShaderManager.CreateGraphicsState({ desc.path, state });
20198bf80f4bSopenharmony_ci        }
20208bf80f4bSopenharmony_ci    }
20218bf80f4bSopenharmony_ci}
20228bf80f4bSopenharmony_ci
20238bf80f4bSopenharmony_cibool SceneHolder::GetGraphicsState(
20248bf80f4bSopenharmony_ci    CORE_NS::Entity materialEntity, ShaderType type, const SCENE_NS::IShaderGraphicsState::Ptr& ret)
20258bf80f4bSopenharmony_ci{
20268bf80f4bSopenharmony_ci    if (!ecs_) {
20278bf80f4bSopenharmony_ci        return false;
20288bf80f4bSopenharmony_ci    }
20298bf80f4bSopenharmony_ci
20308bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
20318bf80f4bSopenharmony_ci        return false;
20328bf80f4bSopenharmony_ci    }
20338bf80f4bSopenharmony_ci
20348bf80f4bSopenharmony_ci    CORE_NS::EntityReference entityRef;
20358bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
20368bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
20378bf80f4bSopenharmony_ci            entityRef = readHandle->materialShader.graphicsState;
20388bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
20398bf80f4bSopenharmony_ci            entityRef = readHandle->depthShader.graphicsState;
20408bf80f4bSopenharmony_ci        }
20418bf80f4bSopenharmony_ci    }
20428bf80f4bSopenharmony_ci    auto rh = rhComponentManager_->GetRenderHandleReference(entityRef);
20438bf80f4bSopenharmony_ci    if (RENDER_NS::RenderHandleUtil::IsValid(rh.GetHandle())) {
20448bf80f4bSopenharmony_ci        auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
20458bf80f4bSopenharmony_ci        auto state = engineShaderManager.GetGraphicsState(rh);
20468bf80f4bSopenharmony_ci        if (auto typed = interface_cast<SCENE_NS::IPendingRequestData<RENDER_NS::GraphicsState>>(ret)) {
20478bf80f4bSopenharmony_ci            typed->Add(state);
20488bf80f4bSopenharmony_ci            return true;
20498bf80f4bSopenharmony_ci        }
20508bf80f4bSopenharmony_ci    }
20518bf80f4bSopenharmony_ci    return false;
20528bf80f4bSopenharmony_ci}
20538bf80f4bSopenharmony_ci
20548bf80f4bSopenharmony_civoid SceneHolder::SetShader(CORE_NS::Entity materialEntity, ShaderType type, SCENE_NS::IShader::Ptr shader)
20558bf80f4bSopenharmony_ci{
20568bf80f4bSopenharmony_ci    if (!ecs_) {
20578bf80f4bSopenharmony_ci        return;
20588bf80f4bSopenharmony_ci    }
20598bf80f4bSopenharmony_ci
20608bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
20618bf80f4bSopenharmony_ci        return;
20628bf80f4bSopenharmony_ci    }
20638bf80f4bSopenharmony_ci
20648bf80f4bSopenharmony_ci    EntityReference shaderEntityRef {};
20658bf80f4bSopenharmony_ci    RenderHandleReference rh {};
20668bf80f4bSopenharmony_ci
20678bf80f4bSopenharmony_ci    auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
20688bf80f4bSopenharmony_ci    if (shader) {
20698bf80f4bSopenharmony_ci        rh = shader->GetRenderHandleReference(engineShaderManager);
20708bf80f4bSopenharmony_ci        auto uri = META_NS::GetValue(shader->Uri());
20718bf80f4bSopenharmony_ci
20728bf80f4bSopenharmony_ci        if (RenderHandleUtil::IsValid(rh.GetHandle())) {
20738bf80f4bSopenharmony_ci            shaderEntityRef = GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, rh);
20748bf80f4bSopenharmony_ci            // Studio used to update also uri component, maybe someone else should do this
20758bf80f4bSopenharmony_ci            // if needed to begin with
20768bf80f4bSopenharmony_ci            if (!uriComponentManager_->HasComponent(shaderEntityRef)) {
20778bf80f4bSopenharmony_ci                uriComponentManager_->Create(shaderEntityRef);
20788bf80f4bSopenharmony_ci            }
20798bf80f4bSopenharmony_ci            if (auto handle = uriComponentManager_->Write(shaderEntityRef)) {
20808bf80f4bSopenharmony_ci                handle->uri = uri;
20818bf80f4bSopenharmony_ci            }
20828bf80f4bSopenharmony_ci        } else {
20838bf80f4bSopenharmony_ci            CORE_LOG_W("Failed to set shader, invalid render handle: %s", uri.c_str());
20848bf80f4bSopenharmony_ci            return;
20858bf80f4bSopenharmony_ci        }
20868bf80f4bSopenharmony_ci        if (auto shref = interface_cast<ISceneHolderRef>(shader)) {
20878bf80f4bSopenharmony_ci            shref->SetSceneHolder(me_);
20888bf80f4bSopenharmony_ci            shref->SetIndex(type);
20898bf80f4bSopenharmony_ci        }
20908bf80f4bSopenharmony_ci    }
20918bf80f4bSopenharmony_ci
20928bf80f4bSopenharmony_ci    // Only writing the value if it has changed.
20938bf80f4bSopenharmony_ci    bool valueChanged = false;
20948bf80f4bSopenharmony_ci
20958bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
20968bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
20978bf80f4bSopenharmony_ci            valueChanged = readHandle->materialShader.shader != shaderEntityRef;
20988bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
20998bf80f4bSopenharmony_ci            valueChanged = readHandle->depthShader.shader != shaderEntityRef;
21008bf80f4bSopenharmony_ci        }
21018bf80f4bSopenharmony_ci    }
21028bf80f4bSopenharmony_ci
21038bf80f4bSopenharmony_ci    if (!valueChanged) {
21048bf80f4bSopenharmony_ci        return;
21058bf80f4bSopenharmony_ci    }
21068bf80f4bSopenharmony_ci
21078bf80f4bSopenharmony_ci    if (auto writeHandle = materialComponentManager_->Write(materialEntity)) {
21088bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
21098bf80f4bSopenharmony_ci            writeHandle->materialShader.shader = shaderEntityRef;
21108bf80f4bSopenharmony_ci            if (!writeHandle->materialShader.graphicsState) {
21118bf80f4bSopenharmony_ci                // initialize the graphics state handle, so we can resolve it later
21128bf80f4bSopenharmony_ci                if (auto graphicsStateHandle = engineShaderManager.GetGraphicsStateHandleByShaderHandle(rh)) {
21138bf80f4bSopenharmony_ci                    writeHandle->materialShader.graphicsState =
21148bf80f4bSopenharmony_ci                        GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, graphicsStateHandle);
21158bf80f4bSopenharmony_ci                }
21168bf80f4bSopenharmony_ci            }
21178bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
21188bf80f4bSopenharmony_ci            writeHandle->depthShader.shader = shaderEntityRef;
21198bf80f4bSopenharmony_ci            if (!writeHandle->depthShader.graphicsState) {
21208bf80f4bSopenharmony_ci                if (auto graphicsStateHandle = engineShaderManager.GetGraphicsStateHandleByShaderHandle(rh)) {
21218bf80f4bSopenharmony_ci                    writeHandle->depthShader.graphicsState =
21228bf80f4bSopenharmony_ci                        GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, graphicsStateHandle);
21238bf80f4bSopenharmony_ci                }
21248bf80f4bSopenharmony_ci            }
21258bf80f4bSopenharmony_ci        }
21268bf80f4bSopenharmony_ci    }
21278bf80f4bSopenharmony_ci
21288bf80f4bSopenharmony_ci    ProcessEvents();
21298bf80f4bSopenharmony_ci}
21308bf80f4bSopenharmony_ci
21318bf80f4bSopenharmony_civoid SceneHolder::SetGraphicsState(CORE_NS::Entity materialEntity, ShaderType type, SCENE_NS::IGraphicsState::Ptr state)
21328bf80f4bSopenharmony_ci{
21338bf80f4bSopenharmony_ci    if (!ecs_) {
21348bf80f4bSopenharmony_ci        return;
21358bf80f4bSopenharmony_ci    }
21368bf80f4bSopenharmony_ci
21378bf80f4bSopenharmony_ci    if (!EntityUtil::IsValid(materialEntity)) {
21388bf80f4bSopenharmony_ci        return;
21398bf80f4bSopenharmony_ci    }
21408bf80f4bSopenharmony_ci
21418bf80f4bSopenharmony_ci    EntityReference stateEntityRef {};
21428bf80f4bSopenharmony_ci    if (state) {
21438bf80f4bSopenharmony_ci        auto& engineShaderManager = renderContext_->GetDevice().GetShaderManager();
21448bf80f4bSopenharmony_ci        auto rh = state->GetRenderHandleReference(engineShaderManager);
21458bf80f4bSopenharmony_ci
21468bf80f4bSopenharmony_ci        if (RenderHandleUtil::IsValid(rh.GetHandle())) {
21478bf80f4bSopenharmony_ci            auto uri = META_NS::GetValue(state->Uri());
21488bf80f4bSopenharmony_ci            auto variant = META_NS::GetValue(state->Variant());
21498bf80f4bSopenharmony_ci
21508bf80f4bSopenharmony_ci            stateEntityRef = GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, rh);
21518bf80f4bSopenharmony_ci            // Studio used to update also uri component, maybe someone else should do this
21528bf80f4bSopenharmony_ci            // if needed to begin with
21538bf80f4bSopenharmony_ci            if (!uriComponentManager_->HasComponent(stateEntityRef)) {
21548bf80f4bSopenharmony_ci                uriComponentManager_->Create(stateEntityRef);
21558bf80f4bSopenharmony_ci            }
21568bf80f4bSopenharmony_ci            if (auto handle = uriComponentManager_->Write(stateEntityRef)) {
21578bf80f4bSopenharmony_ci                handle->uri = uri.append(variant);
21588bf80f4bSopenharmony_ci            }
21598bf80f4bSopenharmony_ci        } else {
21608bf80f4bSopenharmony_ci            CORE_LOG_W("Failed to set shader, invalid render handle: %s", META_NS::GetValue(state->Uri()).c_str());
21618bf80f4bSopenharmony_ci            return;
21628bf80f4bSopenharmony_ci        }
21638bf80f4bSopenharmony_ci        if (auto shref = interface_cast<ISceneHolderRef>(state)) {
21648bf80f4bSopenharmony_ci            shref->SetSceneHolder(me_);
21658bf80f4bSopenharmony_ci            shref->SetIndex(type);
21668bf80f4bSopenharmony_ci        }
21678bf80f4bSopenharmony_ci    }
21688bf80f4bSopenharmony_ci
21698bf80f4bSopenharmony_ci    // Only writing the value if it has changed.
21708bf80f4bSopenharmony_ci    bool valueChanged = false;
21718bf80f4bSopenharmony_ci
21728bf80f4bSopenharmony_ci    if (auto readHandle = materialComponentManager_->Read(materialEntity)) {
21738bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
21748bf80f4bSopenharmony_ci            valueChanged = readHandle->materialShader.graphicsState != stateEntityRef;
21758bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
21768bf80f4bSopenharmony_ci            valueChanged = readHandle->depthShader.graphicsState != stateEntityRef;
21778bf80f4bSopenharmony_ci        }
21788bf80f4bSopenharmony_ci    }
21798bf80f4bSopenharmony_ci
21808bf80f4bSopenharmony_ci    if (!valueChanged) {
21818bf80f4bSopenharmony_ci        return;
21828bf80f4bSopenharmony_ci    }
21838bf80f4bSopenharmony_ci
21848bf80f4bSopenharmony_ci    if (auto writeHandle = materialComponentManager_->Write(materialEntity)) {
21858bf80f4bSopenharmony_ci        if (type == ShaderType::MATERIAL_SHADER) {
21868bf80f4bSopenharmony_ci            writeHandle->materialShader.graphicsState = stateEntityRef;
21878bf80f4bSopenharmony_ci        } else if (type == ShaderType::DEPTH_SHADER) {
21888bf80f4bSopenharmony_ci            writeHandle->depthShader.graphicsState = stateEntityRef;
21898bf80f4bSopenharmony_ci        }
21908bf80f4bSopenharmony_ci    }
21918bf80f4bSopenharmony_ci
21928bf80f4bSopenharmony_ci    ProcessEvents();
21938bf80f4bSopenharmony_ci}
21948bf80f4bSopenharmony_ci
21958bf80f4bSopenharmony_ciBASE_NS::string SceneHolder::GetHandleUri(RENDER_NS::RenderHandleReference renderHandleReference, UriHandleType type)
21968bf80f4bSopenharmony_ci{
21978bf80f4bSopenharmony_ci    if (ecs_ && renderContext_) {
21988bf80f4bSopenharmony_ci        auto& device = renderContext_->GetDevice();
21998bf80f4bSopenharmony_ci
22008bf80f4bSopenharmony_ci        auto& shaderManager = device.GetShaderManager();
22018bf80f4bSopenharmony_ci
22028bf80f4bSopenharmony_ci        if ((type == HANDLE_TYPE_SHADER && shaderManager.IsShader(renderHandleReference)) ||
22038bf80f4bSopenharmony_ci            (type == HANDLE_TYPE_DO_NOT_CARE)) {
22048bf80f4bSopenharmony_ci            auto desc = shaderManager.GetIdDesc(renderHandleReference);
22058bf80f4bSopenharmony_ci            return desc.path;
22068bf80f4bSopenharmony_ci        }
22078bf80f4bSopenharmony_ci    }
22088bf80f4bSopenharmony_ci    return BASE_NS::string();
22098bf80f4bSopenharmony_ci}
22108bf80f4bSopenharmony_ci
22118bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::LoadSampler(BASE_NS::string_view uri)
22128bf80f4bSopenharmony_ci{
22138bf80f4bSopenharmony_ci    CORE_NS::Entity ret;
22148bf80f4bSopenharmony_ci    if (ecs_ && renderContext_) {
22158bf80f4bSopenharmony_ci        const auto name = uri.substr(ENGINE_URI_PREFIX_LEN);
22168bf80f4bSopenharmony_ci        auto linearHandle = renderContext_->GetDevice().GetGpuResourceManager().GetSamplerHandle(name);
22178bf80f4bSopenharmony_ci
22188bf80f4bSopenharmony_ci        auto entity = rhComponentManager_->GetEntityWithReference(linearHandle);
22198bf80f4bSopenharmony_ci        if (!EntityUtil::IsValid(entity)) {
22208bf80f4bSopenharmony_ci            // No existing sampler found, prepare one
22218bf80f4bSopenharmony_ci            auto uriManager = GetManager<CORE3D_NS::IUriComponentManager>(*ecs_);
22228bf80f4bSopenharmony_ci            entity = ecs_->GetEntityManager().Create();
22238bf80f4bSopenharmony_ci
22248bf80f4bSopenharmony_ci            uriManager->Create(entity);
22258bf80f4bSopenharmony_ci            uriManager->Write(entity)->uri = uri;
22268bf80f4bSopenharmony_ci
22278bf80f4bSopenharmony_ci            rhComponentManager_->Create(entity);
22288bf80f4bSopenharmony_ci            rhComponentManager_->Write(entity)->reference = linearHandle;
22298bf80f4bSopenharmony_ci
22308bf80f4bSopenharmony_ci            RenameEntity(entity, BASE_NS::string(name.data(), name.size()));
22318bf80f4bSopenharmony_ci            scene_->AddEntityToSubcollection("samplers", name, entity, false);
22328bf80f4bSopenharmony_ci        }
22338bf80f4bSopenharmony_ci        ret = entity;
22348bf80f4bSopenharmony_ci    }
22358bf80f4bSopenharmony_ci
22368bf80f4bSopenharmony_ci    return ret;
22378bf80f4bSopenharmony_ci}
22388bf80f4bSopenharmony_ci
22398bf80f4bSopenharmony_ciCORE_NS::EntityReference SceneHolder::LoadImage(BASE_NS::string_view uri, RENDER_NS::RenderHandleReference rh)
22408bf80f4bSopenharmony_ci{
22418bf80f4bSopenharmony_ci    CORE_NS::Entity ret;
22428bf80f4bSopenharmony_ci    if (FindResource(uri, uri, ret)) {
22438bf80f4bSopenharmony_ci        return ecs_->GetEntityManager().GetReferenceCounted(ret);
22448bf80f4bSopenharmony_ci    }
22458bf80f4bSopenharmony_ci
22468bf80f4bSopenharmony_ci    if (scene_ && assetManager_) {
22478bf80f4bSopenharmony_ci        RENDER_NS::RenderHandleReference imageHandle;
22488bf80f4bSopenharmony_ci        if (rh) {
22498bf80f4bSopenharmony_ci            imageHandle = rh;
22508bf80f4bSopenharmony_ci        } else {
22518bf80f4bSopenharmony_ci            imageHandle = assetManager_->GetEcsSerializer().LoadImageResource(uri);
22528bf80f4bSopenharmony_ci        }
22538bf80f4bSopenharmony_ci        if (imageHandle) {
22548bf80f4bSopenharmony_ci            return GetOrCreateEntityReference(ecs_->GetEntityManager(), *rhComponentManager_, imageHandle);
22558bf80f4bSopenharmony_ci        }
22568bf80f4bSopenharmony_ci    }
22578bf80f4bSopenharmony_ci
22588bf80f4bSopenharmony_ci    return {};
22598bf80f4bSopenharmony_ci}
22608bf80f4bSopenharmony_ci
22618bf80f4bSopenharmony_civoid SceneHolder::SetSampler(size_t index, CORE_NS::Entity targetEntity, SCENE_NS::ITextureInfo::SamplerId samplerId)
22628bf80f4bSopenharmony_ci{
22638bf80f4bSopenharmony_ci    if (ecs_) {
22648bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
22658bf80f4bSopenharmony_ci            bool wrote = false;
22668bf80f4bSopenharmony_ci            if (auto handle = materialComponentManager_->Write(targetEntity)) {
22678bf80f4bSopenharmony_ci                auto entity = LoadSampler(ResolveSamplerUri(samplerId));
22688bf80f4bSopenharmony_ci                if (EntityUtil::IsValid(entity)) {
22698bf80f4bSopenharmony_ci                    // both scene and texture array will hold a reference to entity
22708bf80f4bSopenharmony_ci                    handle->textures[index].sampler = ecs_->GetEntityManager().GetReferenceCounted(entity);
22718bf80f4bSopenharmony_ci                    wrote = true;
22728bf80f4bSopenharmony_ci                }
22738bf80f4bSopenharmony_ci            }
22748bf80f4bSopenharmony_ci            if (wrote) {
22758bf80f4bSopenharmony_ci                ProcessEvents();
22768bf80f4bSopenharmony_ci            }
22778bf80f4bSopenharmony_ci        }
22788bf80f4bSopenharmony_ci    }
22798bf80f4bSopenharmony_ci}
22808bf80f4bSopenharmony_ci
22818bf80f4bSopenharmony_civoid SceneHolder::SetSubmeshRenderSortOrder(CORE_NS::Entity targetEntity, int64_t submeshIndex, uint8_t value)
22828bf80f4bSopenharmony_ci{
22838bf80f4bSopenharmony_ci    if (ecs_) {
22848bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
22858bf80f4bSopenharmony_ci            bool wrote = false;
22868bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Write(targetEntity)) {
22878bf80f4bSopenharmony_ci                if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
22888bf80f4bSopenharmony_ci                    handle->submeshes[submeshIndex].renderSortLayerOrder = value;
22898bf80f4bSopenharmony_ci                    wrote = true;
22908bf80f4bSopenharmony_ci                }
22918bf80f4bSopenharmony_ci            }
22928bf80f4bSopenharmony_ci            if (wrote) {
22938bf80f4bSopenharmony_ci                ProcessEvents();
22948bf80f4bSopenharmony_ci            }
22958bf80f4bSopenharmony_ci        }
22968bf80f4bSopenharmony_ci    }
22978bf80f4bSopenharmony_ci}
22988bf80f4bSopenharmony_ci
22998bf80f4bSopenharmony_civoid SceneHolder::SetSubmeshAABBMin(CORE_NS::Entity targetEntity, int64_t submeshIndex, const BASE_NS::Math::Vec3& vec)
23008bf80f4bSopenharmony_ci{
23018bf80f4bSopenharmony_ci    if (ecs_) {
23028bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
23038bf80f4bSopenharmony_ci            bool wrote = false;
23048bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Write(targetEntity)) {
23058bf80f4bSopenharmony_ci                if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
23068bf80f4bSopenharmony_ci                    handle->submeshes[submeshIndex].aabbMin = vec;
23078bf80f4bSopenharmony_ci                    handle->aabbMin = min(handle->aabbMin, vec);
23088bf80f4bSopenharmony_ci                    wrote = true;
23098bf80f4bSopenharmony_ci                }
23108bf80f4bSopenharmony_ci            }
23118bf80f4bSopenharmony_ci            if (wrote) {
23128bf80f4bSopenharmony_ci                ProcessEvents();
23138bf80f4bSopenharmony_ci            }
23148bf80f4bSopenharmony_ci        }
23158bf80f4bSopenharmony_ci    }
23168bf80f4bSopenharmony_ci}
23178bf80f4bSopenharmony_ci
23188bf80f4bSopenharmony_civoid SceneHolder::RemoveSubmesh(CORE_NS::Entity targetEntity, int64_t submeshIndex)
23198bf80f4bSopenharmony_ci{
23208bf80f4bSopenharmony_ci    if (ecs_) {
23218bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
23228bf80f4bSopenharmony_ci            bool wrote = false;
23238bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Write(targetEntity)) {
23248bf80f4bSopenharmony_ci                if (submeshIndex < 0) {
23258bf80f4bSopenharmony_ci                    handle->submeshes.clear();
23268bf80f4bSopenharmony_ci                    handle->aabbMin = { 0.f, 0.f, 0.f };
23278bf80f4bSopenharmony_ci                    handle->aabbMax = { 0.f, 0.f, 0.f };
23288bf80f4bSopenharmony_ci                    wrote = true;
23298bf80f4bSopenharmony_ci                } else if (submeshIndex < handle->submeshes.size()) {
23308bf80f4bSopenharmony_ci                    handle->submeshes.erase(handle->submeshes.begin() + submeshIndex);
23318bf80f4bSopenharmony_ci                    for (const auto& submesh : handle->submeshes) {
23328bf80f4bSopenharmony_ci                        handle->aabbMin = BASE_NS::Math::min(handle->aabbMin, submesh.aabbMin);
23338bf80f4bSopenharmony_ci                        handle->aabbMax = BASE_NS::Math::max(handle->aabbMax, submesh.aabbMax);
23348bf80f4bSopenharmony_ci                    }
23358bf80f4bSopenharmony_ci                    wrote = true;
23368bf80f4bSopenharmony_ci                }
23378bf80f4bSopenharmony_ci            }
23388bf80f4bSopenharmony_ci            if (wrote) {
23398bf80f4bSopenharmony_ci                ProcessEvents();
23408bf80f4bSopenharmony_ci            }
23418bf80f4bSopenharmony_ci        }
23428bf80f4bSopenharmony_ci    }
23438bf80f4bSopenharmony_ci}
23448bf80f4bSopenharmony_ci
23458bf80f4bSopenharmony_civoid SceneHolder::SetSubmeshAABBMax(CORE_NS::Entity targetEntity, int64_t submeshIndex, const BASE_NS::Math::Vec3& vec)
23468bf80f4bSopenharmony_ci{
23478bf80f4bSopenharmony_ci    if (ecs_) {
23488bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(targetEntity)) {
23498bf80f4bSopenharmony_ci            bool wrote = false;
23508bf80f4bSopenharmony_ci            if (auto handle = meshComponentManager_->Write(targetEntity)) {
23518bf80f4bSopenharmony_ci                if (submeshIndex >= 0 && submeshIndex < handle->submeshes.size()) {
23528bf80f4bSopenharmony_ci                    handle->submeshes[submeshIndex].aabbMax = vec;
23538bf80f4bSopenharmony_ci                    handle->aabbMax = max(handle->aabbMax, vec);
23548bf80f4bSopenharmony_ci                    wrote = true;
23558bf80f4bSopenharmony_ci                }
23568bf80f4bSopenharmony_ci            }
23578bf80f4bSopenharmony_ci            if (wrote) {
23588bf80f4bSopenharmony_ci                ProcessEvents();
23598bf80f4bSopenharmony_ci            }
23608bf80f4bSopenharmony_ci        }
23618bf80f4bSopenharmony_ci    }
23628bf80f4bSopenharmony_ci}
23638bf80f4bSopenharmony_ci
23648bf80f4bSopenharmony_civoid SceneHolder::EnableEnvironmentComponent(CORE_NS::Entity entity)
23658bf80f4bSopenharmony_ci{
23668bf80f4bSopenharmony_ci    if (ecs_) {
23678bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
23688bf80f4bSopenharmony_ci            if (!envComponentManager_->HasComponent(entity)) {
23698bf80f4bSopenharmony_ci                envComponentManager_->Create(entity);
23708bf80f4bSopenharmony_ci            }
23718bf80f4bSopenharmony_ci        }
23728bf80f4bSopenharmony_ci    }
23738bf80f4bSopenharmony_ci}
23748bf80f4bSopenharmony_ci
23758bf80f4bSopenharmony_civoid SceneHolder::EnableLayerComponent(CORE_NS::Entity entity)
23768bf80f4bSopenharmony_ci{
23778bf80f4bSopenharmony_ci    if (ecs_) {
23788bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
23798bf80f4bSopenharmony_ci            if (!layerComponentManager_->HasComponent(entity)) {
23808bf80f4bSopenharmony_ci                layerComponentManager_->Create(entity);
23818bf80f4bSopenharmony_ci            }
23828bf80f4bSopenharmony_ci        }
23838bf80f4bSopenharmony_ci    }
23848bf80f4bSopenharmony_ci}
23858bf80f4bSopenharmony_ci
23868bf80f4bSopenharmony_civoid SceneHolder::EnableLightComponent(CORE_NS::Entity entity)
23878bf80f4bSopenharmony_ci{
23888bf80f4bSopenharmony_ci    if (ecs_) {
23898bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
23908bf80f4bSopenharmony_ci            if (!lightComponentManager_->HasComponent(entity)) {
23918bf80f4bSopenharmony_ci                lightComponentManager_->Create(entity);
23928bf80f4bSopenharmony_ci            }
23938bf80f4bSopenharmony_ci        }
23948bf80f4bSopenharmony_ci    }
23958bf80f4bSopenharmony_ci}
23968bf80f4bSopenharmony_ci
23978bf80f4bSopenharmony_citemplate<typename T>
23988bf80f4bSopenharmony_ciconstexpr inline CORE3D_NS::IMeshBuilder::DataBuffer FillData(array_view<const T> c) noexcept
23998bf80f4bSopenharmony_ci{
24008bf80f4bSopenharmony_ci    Format format = BASE_FORMAT_UNDEFINED;
24018bf80f4bSopenharmony_ci    if constexpr (is_same_v<T, Math::Vec2>) {
24028bf80f4bSopenharmony_ci        format = BASE_FORMAT_R32G32_SFLOAT;
24038bf80f4bSopenharmony_ci    } else if constexpr (is_same_v<T, Math::Vec3>) {
24048bf80f4bSopenharmony_ci        format = BASE_FORMAT_R32G32B32_SFLOAT;
24058bf80f4bSopenharmony_ci    } else if constexpr (is_same_v<T, Math::Vec4>) {
24068bf80f4bSopenharmony_ci        format = BASE_FORMAT_R32G32B32A32_SFLOAT;
24078bf80f4bSopenharmony_ci    } else if constexpr (is_same_v<T, uint16_t>) {
24088bf80f4bSopenharmony_ci        format = BASE_FORMAT_R16_UINT;
24098bf80f4bSopenharmony_ci    } else if constexpr (is_same_v<T, uint32_t>) {
24108bf80f4bSopenharmony_ci        format = BASE_FORMAT_R32_UINT;
24118bf80f4bSopenharmony_ci    }
24128bf80f4bSopenharmony_ci    return CORE3D_NS::IMeshBuilder::DataBuffer { format, sizeof(T),
24138bf80f4bSopenharmony_ci        { reinterpret_cast<const uint8_t*>(c.data()), c.size() * sizeof(T) } };
24148bf80f4bSopenharmony_ci}
24158bf80f4bSopenharmony_ci
24168bf80f4bSopenharmony_citemplate<typename IndicesType>
24178bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateMeshFromArrays(const BASE_NS::string& name,
24188bf80f4bSopenharmony_ci    SCENE_NS::MeshGeometryArrayPtr<IndicesType> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
24198bf80f4bSopenharmony_ci    bool append)
24208bf80f4bSopenharmony_ci{
24218bf80f4bSopenharmony_ci    if (!ecs_) {
24228bf80f4bSopenharmony_ci        CORE_LOG_W("%s: no ecs, cannot create mesh", __func__);
24238bf80f4bSopenharmony_ci        return {};
24248bf80f4bSopenharmony_ci    }
24258bf80f4bSopenharmony_ci
24268bf80f4bSopenharmony_ci    if (!arrays || arrays->size() == 0) {
24278bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(existingEntity)) {
24288bf80f4bSopenharmony_ci            RemoveSubmesh(existingEntity, -1);
24298bf80f4bSopenharmony_ci            return existingEntity;
24308bf80f4bSopenharmony_ci        } else {
24318bf80f4bSopenharmony_ci            // create empty, submeshes may follow
24328bf80f4bSopenharmony_ci            auto entity = ecs_->GetEntityManager().Create();
24338bf80f4bSopenharmony_ci
24348bf80f4bSopenharmony_ci            RenameEntity(entity, name);
24358bf80f4bSopenharmony_ci
24368bf80f4bSopenharmony_ci            meshComponentManager_->Create(entity);
24378bf80f4bSopenharmony_ci            scene_->AddEntityToSubcollection("created_meshes", name, entity);
24388bf80f4bSopenharmony_ci            return entity;
24398bf80f4bSopenharmony_ci        }
24408bf80f4bSopenharmony_ci    }
24418bf80f4bSopenharmony_ci
24428bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(existingEntity) && !append) {
24438bf80f4bSopenharmony_ci        RemoveSubmesh(existingEntity, -1);
24448bf80f4bSopenharmony_ci    }
24458bf80f4bSopenharmony_ci
24468bf80f4bSopenharmony_ci    size_t subMeshIndex = 0;
24478bf80f4bSopenharmony_ci    auto meshBuilder = CORE_NS::CreateInstance<CORE3D_NS::IMeshBuilder>(*renderContext_, CORE3D_NS::UID_MESH_BUILDER);
24488bf80f4bSopenharmony_ci
24498bf80f4bSopenharmony_ci    RENDER_NS::IShaderManager& shaderManager = renderContext_->GetDevice().GetShaderManager();
24508bf80f4bSopenharmony_ci    const RENDER_NS::VertexInputDeclarationView vertexInputDeclaration =
24518bf80f4bSopenharmony_ci        shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
24528bf80f4bSopenharmony_ci            CORE3D_NS::DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
24538bf80f4bSopenharmony_ci
24548bf80f4bSopenharmony_ci    meshBuilder->Initialize(vertexInputDeclaration, 1);
24558bf80f4bSopenharmony_ci
24568bf80f4bSopenharmony_ci    for (auto&& geometry : *arrays.get()) {
24578bf80f4bSopenharmony_ci        CORE3D_NS::IMeshBuilder::Submesh submesh;
24588bf80f4bSopenharmony_ci
24598bf80f4bSopenharmony_ci        submesh.indexType = indexType;
24608bf80f4bSopenharmony_ci        submesh.vertexCount = static_cast<uint32_t>(geometry->vertices.size());
24618bf80f4bSopenharmony_ci        submesh.indexCount = static_cast<uint32_t>(geometry->indices.size());
24628bf80f4bSopenharmony_ci        submesh.tangents = geometry->generateTangents;
24638bf80f4bSopenharmony_ci
24648bf80f4bSopenharmony_ci        meshBuilder->AddSubmesh(submesh);
24658bf80f4bSopenharmony_ci    }
24668bf80f4bSopenharmony_ci    meshBuilder->Allocate();
24678bf80f4bSopenharmony_ci
24688bf80f4bSopenharmony_ci    for (auto&& geometry : *arrays.get()) {
24698bf80f4bSopenharmony_ci        meshBuilder->SetVertexData(subMeshIndex, FillData<BASE_NS::Math::Vec3>(geometry->vertices),
24708bf80f4bSopenharmony_ci            FillData<BASE_NS::Math::Vec3>(geometry->normals), FillData<BASE_NS::Math::Vec2>(geometry->uvs),
24718bf80f4bSopenharmony_ci            FillData<BASE_NS::Math::Vec2>(geometry->uv2s), FillData<BASE_NS::Math::Vec4>(geometry->tangents),
24728bf80f4bSopenharmony_ci            FillData<BASE_NS::Math::Vec4>(geometry->colors));
24738bf80f4bSopenharmony_ci        meshBuilder->CalculateAABB(subMeshIndex, FillData<BASE_NS::Math::Vec3>(geometry->vertices));
24748bf80f4bSopenharmony_ci        meshBuilder->SetIndexData(subMeshIndex, FillData<IndicesType>(geometry->indices));
24758bf80f4bSopenharmony_ci    }
24768bf80f4bSopenharmony_ci
24778bf80f4bSopenharmony_ci    auto entity = meshBuilder->CreateMesh(*ecs_);
24788bf80f4bSopenharmony_ci
24798bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(existingEntity)) {
24808bf80f4bSopenharmony_ci        for (size_t ii = 0; ii < arrays->size(); ii++) {
24818bf80f4bSopenharmony_ci            CopySubMesh(existingEntity, entity, ii);
24828bf80f4bSopenharmony_ci        }
24838bf80f4bSopenharmony_ci        ecs_->GetEntityManager().Destroy(entity);
24848bf80f4bSopenharmony_ci        return existingEntity;
24858bf80f4bSopenharmony_ci    }
24868bf80f4bSopenharmony_ci
24878bf80f4bSopenharmony_ci    RenameEntity(entity, name);
24888bf80f4bSopenharmony_ci    scene_->AddEntityToSubcollection("created_meshes", name, entity);
24898bf80f4bSopenharmony_ci
24908bf80f4bSopenharmony_ci    ProcessEvents();
24918bf80f4bSopenharmony_ci    return entity;
24928bf80f4bSopenharmony_ci}
24938bf80f4bSopenharmony_ci
24948bf80f4bSopenharmony_ci// we rely that someone else will ret up correct flags to components
24958bf80f4bSopenharmony_civoid SceneHolder::SetMultiviewCamera(CORE_NS::Entity target, CORE_NS::Entity source)
24968bf80f4bSopenharmony_ci{
24978bf80f4bSopenharmony_ci    if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
24988bf80f4bSopenharmony_ci        !cameraComponentManager_->HasComponent(source) || !cameraComponentManager_->HasComponent(target)) {
24998bf80f4bSopenharmony_ci        CORE_LOG_W("%s: camera component not valid", __func__);
25008bf80f4bSopenharmony_ci        return;
25018bf80f4bSopenharmony_ci    }
25028bf80f4bSopenharmony_ci    if (auto handle = cameraComponentManager_->Write(target)) {
25038bf80f4bSopenharmony_ci        for (auto& ref : handle->multiViewCameras) {
25048bf80f4bSopenharmony_ci            if (ref.id == target.id) {
25058bf80f4bSopenharmony_ci                return;
25068bf80f4bSopenharmony_ci            }
25078bf80f4bSopenharmony_ci        }
25088bf80f4bSopenharmony_ci        handle->multiViewCameras.push_back(source);
25098bf80f4bSopenharmony_ci    }
25108bf80f4bSopenharmony_ci}
25118bf80f4bSopenharmony_ci
25128bf80f4bSopenharmony_ci// we rely that someone else will ret up correct flags to components
25138bf80f4bSopenharmony_civoid SceneHolder::RemoveMultiviewCamera(CORE_NS::Entity target, CORE_NS::Entity source)
25148bf80f4bSopenharmony_ci{
25158bf80f4bSopenharmony_ci    if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
25168bf80f4bSopenharmony_ci        !cameraComponentManager_->HasComponent(source) || !cameraComponentManager_->HasComponent(target)) {
25178bf80f4bSopenharmony_ci        CORE_LOG_W("%s: camera component not valid", __func__);
25188bf80f4bSopenharmony_ci        return;
25198bf80f4bSopenharmony_ci    }
25208bf80f4bSopenharmony_ci    if (auto handle = cameraComponentManager_->Write(target)) {
25218bf80f4bSopenharmony_ci        for (size_t ii = 0; ii < handle->multiViewCameras.size(); ii++) {
25228bf80f4bSopenharmony_ci            if (handle->multiViewCameras[ii] == target) {
25238bf80f4bSopenharmony_ci                handle->multiViewCameras.erase(handle->multiViewCameras.cbegin() + ii);
25248bf80f4bSopenharmony_ci                return;
25258bf80f4bSopenharmony_ci            }
25268bf80f4bSopenharmony_ci        }
25278bf80f4bSopenharmony_ci    }
25288bf80f4bSopenharmony_ci}
25298bf80f4bSopenharmony_ci
25308bf80f4bSopenharmony_civoid SceneHolder::CopySubMesh(CORE_NS::Entity target, CORE_NS::Entity source, size_t index)
25318bf80f4bSopenharmony_ci{
25328bf80f4bSopenharmony_ci    if (!ecs_ || !EntityUtil::IsValid(target) || !EntityUtil::IsValid(source) ||
25338bf80f4bSopenharmony_ci        !meshComponentManager_->HasComponent(source)) {
25348bf80f4bSopenharmony_ci        CORE_LOG_W("%s: cannot copy submesh", __func__);
25358bf80f4bSopenharmony_ci        return;
25368bf80f4bSopenharmony_ci    }
25378bf80f4bSopenharmony_ci
25388bf80f4bSopenharmony_ci    bool wrote = false;
25398bf80f4bSopenharmony_ci    if (auto sourceComponent = meshComponentManager_->Read(source)) {
25408bf80f4bSopenharmony_ci        if (sourceComponent->submeshes.size() > index) {
25418bf80f4bSopenharmony_ci            if (!meshComponentManager_->HasComponent(target)) {
25428bf80f4bSopenharmony_ci                meshComponentManager_->Create(target);
25438bf80f4bSopenharmony_ci            }
25448bf80f4bSopenharmony_ci            if (auto targetComponent = meshComponentManager_->Write(target)) {
25458bf80f4bSopenharmony_ci                targetComponent->submeshes.push_back(CORE3D_NS::MeshComponent::Submesh());
25468bf80f4bSopenharmony_ci                // Todo: verify if copy by assignment is enough, or do we need deep copy
25478bf80f4bSopenharmony_ci                // and explicit reference modifications
25488bf80f4bSopenharmony_ci                targetComponent->submeshes.back() = sourceComponent->submeshes.at(index);
25498bf80f4bSopenharmony_ci                for (const auto& submesh : targetComponent->submeshes) {
25508bf80f4bSopenharmony_ci                    targetComponent->aabbMin = BASE_NS::Math::min(targetComponent->aabbMin, submesh.aabbMin);
25518bf80f4bSopenharmony_ci                    targetComponent->aabbMax = BASE_NS::Math::max(targetComponent->aabbMax, submesh.aabbMax);
25528bf80f4bSopenharmony_ci                }
25538bf80f4bSopenharmony_ci                wrote = true;
25548bf80f4bSopenharmony_ci            }
25558bf80f4bSopenharmony_ci        }
25568bf80f4bSopenharmony_ci    }
25578bf80f4bSopenharmony_ci    if (wrote) {
25588bf80f4bSopenharmony_ci        ProcessEvents();
25598bf80f4bSopenharmony_ci    }
25608bf80f4bSopenharmony_ci}
25618bf80f4bSopenharmony_ci
25628bf80f4bSopenharmony_civoid SceneHolder::ReleaseOwnership(CORE_NS::Entity entity)
25638bf80f4bSopenharmony_ci{
25648bf80f4bSopenharmony_ci    if (ecs_ && scene_) {
25658bf80f4bSopenharmony_ci        if (EntityUtil::IsValid(entity)) {
25668bf80f4bSopenharmony_ci            if (const auto cachedEntity = FindCachedRelatedEntity(entity);
25678bf80f4bSopenharmony_ci                EntityUtil::IsValid(cachedEntity) && entity != cachedEntity) {
25688bf80f4bSopenharmony_ci                SCENE_PLUGIN_VERBOSE_LOG("%s: Cached entity does not match: entity: %I64u, cachedEntity: %I64u",
25698bf80f4bSopenharmony_ci                    __func__, entity.id, cachedEntity.id);
25708bf80f4bSopenharmony_ci                if (auto cachedIdx = scene_->GetSubCollectionIndexByRoot(cachedEntity); cachedIdx != -1) {
25718bf80f4bSopenharmony_ci                    scene_->GetSubCollection(cachedIdx)->SetActive(false);
25728bf80f4bSopenharmony_ci                    scene_->RemoveEntityRecursive(cachedEntity);
25738bf80f4bSopenharmony_ci                }
25748bf80f4bSopenharmony_ci            }
25758bf80f4bSopenharmony_ci            scene_->RemoveEntityRecursive(entity);
25768bf80f4bSopenharmony_ci        }
25778bf80f4bSopenharmony_ci    }
25788bf80f4bSopenharmony_ci}
25798bf80f4bSopenharmony_ci
25808bf80f4bSopenharmony_ci// Reposition a node within its parent
25818bf80f4bSopenharmony_civoid SceneHolder::ReindexEntity(CORE_NS::Entity target, size_t index)
25828bf80f4bSopenharmony_ci{
25838bf80f4bSopenharmony_ci    if (ecs_ && scene_ && EntityUtil::IsValid(target)) {
25848bf80f4bSopenharmony_ci        // Get the node
25858bf80f4bSopenharmony_ci        if (auto node = nodeSystem_->GetNode(target)) {
25868bf80f4bSopenharmony_ci            // Get the parent
25878bf80f4bSopenharmony_ci            if (auto parent = node->GetParent()) {
25888bf80f4bSopenharmony_ci                parent->RemoveChild(*node);
25898bf80f4bSopenharmony_ci                parent->InsertChild(index, *node);
25908bf80f4bSopenharmony_ci            }
25918bf80f4bSopenharmony_ci        }
25928bf80f4bSopenharmony_ci
25938bf80f4bSopenharmony_ci        // do we need to adjust also collection manually (it should be reference only)
25948bf80f4bSopenharmony_ci        scene_->MarkModified(true, true);
25958bf80f4bSopenharmony_ci    }
25968bf80f4bSopenharmony_ci}
25978bf80f4bSopenharmony_ci
25988bf80f4bSopenharmony_citemplate CORE_NS::Entity SceneHolder::CreateMeshFromArrays<uint16_t>(const BASE_NS::string& name,
25998bf80f4bSopenharmony_ci    SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
26008bf80f4bSopenharmony_ci    bool append);
26018bf80f4bSopenharmony_ci
26028bf80f4bSopenharmony_citemplate CORE_NS::Entity SceneHolder::CreateMeshFromArrays<uint32_t>(const BASE_NS::string& name,
26038bf80f4bSopenharmony_ci    SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays, RENDER_NS::IndexType indexType, Entity existingEntity,
26048bf80f4bSopenharmony_ci    bool append);
26058bf80f4bSopenharmony_ci
26068bf80f4bSopenharmony_cistring SceneHolder::GetUniqueName()
26078bf80f4bSopenharmony_ci{
26088bf80f4bSopenharmony_ci    return instanceId_.ToString().append(to_string(++instanceNumber_));
26098bf80f4bSopenharmony_ci}
26108bf80f4bSopenharmony_ci
26118bf80f4bSopenharmony_ci// Enable new multi-mesh batch
26128bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::CreateMultiMeshInstance(CORE_NS::Entity baseComponent)
26138bf80f4bSopenharmony_ci{
26148bf80f4bSopenharmony_ci    if (ecs_) {
26158bf80f4bSopenharmony_ci        if (!nodeSystem_->GetNode(baseComponent)) {
26168bf80f4bSopenharmony_ci            CORE_LOG_I("%s: selected base entity does not have node on ecs", __func__);
26178bf80f4bSopenharmony_ci
26188bf80f4bSopenharmony_ci            // Now, the assumption is that entity should have either RenderMeshComponent or MeshComponent
26198bf80f4bSopenharmony_ci            // It is bit open if it has render mesh component, shoud we copy its mesh data implicitly
26208bf80f4bSopenharmony_ci            CORE3D_NS::RenderMeshComponent renderMeshData;
26218bf80f4bSopenharmony_ci
26228bf80f4bSopenharmony_ci            if (auto data = renderMeshComponentManager_->Read(baseComponent)) {
26238bf80f4bSopenharmony_ci                renderMeshData = *data;
26248bf80f4bSopenharmony_ci            }
26258bf80f4bSopenharmony_ci
26268bf80f4bSopenharmony_ci            auto node = nodeSystem_->CreateNode();
26278bf80f4bSopenharmony_ci            auto nodeEntity = node->GetEntity();
26288bf80f4bSopenharmony_ci
26298bf80f4bSopenharmony_ci            renderMeshComponentManager_->Create(nodeEntity);
26308bf80f4bSopenharmony_ci            if (auto data = renderMeshComponentManager_->Write(nodeEntity)) {
26318bf80f4bSopenharmony_ci                *data = renderMeshData;
26328bf80f4bSopenharmony_ci
26338bf80f4bSopenharmony_ci                if (!EntityUtil::IsValid(data->mesh)) {
26348bf80f4bSopenharmony_ci                    // base component may have mesh component, or then it does not
26358bf80f4bSopenharmony_ci                    data->mesh = baseComponent;
26368bf80f4bSopenharmony_ci                }
26378bf80f4bSopenharmony_ci            }
26388bf80f4bSopenharmony_ci            baseComponent = nodeEntity;
26398bf80f4bSopenharmony_ci        }
26408bf80f4bSopenharmony_ci
26418bf80f4bSopenharmony_ci        if (!renderMeshComponentManager_->HasComponent(baseComponent)) {
26428bf80f4bSopenharmony_ci            renderMeshComponentManager_->Create(baseComponent);
26438bf80f4bSopenharmony_ci        }
26448bf80f4bSopenharmony_ci    }
26458bf80f4bSopenharmony_ci
26468bf80f4bSopenharmony_ci    return baseComponent;
26478bf80f4bSopenharmony_ci}
26488bf80f4bSopenharmony_ci
26498bf80f4bSopenharmony_cistatic constexpr size_t MULTI_MESH_CHILD_PREFIX_LEN = MULTI_MESH_CHILD_PREFIX.size();
26508bf80f4bSopenharmony_ci
26518bf80f4bSopenharmony_cibool SceneHolder::IsMultiMeshChild(const CORE3D_NS::ISceneNode* child)
26528bf80f4bSopenharmony_ci{
26538bf80f4bSopenharmony_ci    auto entity = child->GetEntity();
26548bf80f4bSopenharmony_ci    if (auto nameHandle = nameComponentManager_->Read(entity)) {
26558bf80f4bSopenharmony_ci        auto name = BASE_NS::string_view(nameHandle->name.data(), nameHandle->name.size());
26568bf80f4bSopenharmony_ci        if (name.compare(0, MULTI_MESH_CHILD_PREFIX_LEN, MULTI_MESH_CHILD_PREFIX) == 0) {
26578bf80f4bSopenharmony_ci            return true;
26588bf80f4bSopenharmony_ci        }
26598bf80f4bSopenharmony_ci    }
26608bf80f4bSopenharmony_ci    return false;
26618bf80f4bSopenharmony_ci}
26628bf80f4bSopenharmony_ci
26638bf80f4bSopenharmony_ciCORE_NS::Entity SceneHolder::FindCachedRelatedEntity(const CORE_NS::Entity& entity)
26648bf80f4bSopenharmony_ci{
26658bf80f4bSopenharmony_ci    if (!(scene_ && nodeSystem_ && CORE_NS::EntityUtil::IsValid(entity))) {
26668bf80f4bSopenharmony_ci        return {};
26678bf80f4bSopenharmony_ci    }
26688bf80f4bSopenharmony_ci
26698bf80f4bSopenharmony_ci    CORE_NS::Entity cachedEntity {};
26708bf80f4bSopenharmony_ci    if (const auto node = nodeSystem_->GetNode(entity)) {
26718bf80f4bSopenharmony_ci        if (const auto idx = scene_->GetSubCollectionIndex(node->GetName()); idx != -1) {
26728bf80f4bSopenharmony_ci            cachedEntity = scene_->GetSubCollection(idx)->GetEntity("/");
26738bf80f4bSopenharmony_ci        }
26748bf80f4bSopenharmony_ci    }
26758bf80f4bSopenharmony_ci
26768bf80f4bSopenharmony_ci    return cachedEntity;
26778bf80f4bSopenharmony_ci}
26788bf80f4bSopenharmony_ci
26798bf80f4bSopenharmony_ci// Set mesh to multi-mesh
26808bf80f4bSopenharmony_civoid SceneHolder::SetMeshMultimeshArray(CORE_NS::Entity target, CORE_NS::Entity mesh)
26818bf80f4bSopenharmony_ci{
26828bf80f4bSopenharmony_ci    if (ecs_) {
26838bf80f4bSopenharmony_ci        if (auto data = renderMeshComponentManager_->Write(target)) {
26848bf80f4bSopenharmony_ci            data->mesh = mesh;
26858bf80f4bSopenharmony_ci        }
26868bf80f4bSopenharmony_ci
26878bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
26888bf80f4bSopenharmony_ci            MeshComponent givenData;
26898bf80f4bSopenharmony_ci            if (auto givenMeshData = meshComponentManager_->Read(mesh)) {
26908bf80f4bSopenharmony_ci                givenData = *givenMeshData;
26918bf80f4bSopenharmony_ci            }
26928bf80f4bSopenharmony_ci
26938bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
26948bf80f4bSopenharmony_ci                auto entity = child->GetEntity();
26958bf80f4bSopenharmony_ci                if (!IsMultiMeshChild(child)) {
26968bf80f4bSopenharmony_ci                    continue;
26978bf80f4bSopenharmony_ci                }
26988bf80f4bSopenharmony_ci
26998bf80f4bSopenharmony_ci                if (auto data = renderMeshComponentManager_->Read(entity)) {
27008bf80f4bSopenharmony_ci                    auto mesh = data->mesh;
27018bf80f4bSopenharmony_ci                    if (auto meshData = meshComponentManager_->Write(mesh)) {
27028bf80f4bSopenharmony_ci                        *meshData = givenData;
27038bf80f4bSopenharmony_ci                    }
27048bf80f4bSopenharmony_ci                }
27058bf80f4bSopenharmony_ci
27068bf80f4bSopenharmony_ci                if (auto data = renderMeshComponentManager_->Write(entity)) {
27078bf80f4bSopenharmony_ci                    data->renderMeshBatch = target;
27088bf80f4bSopenharmony_ci                }
27098bf80f4bSopenharmony_ci            }
27108bf80f4bSopenharmony_ci        }
27118bf80f4bSopenharmony_ci    }
27128bf80f4bSopenharmony_ci}
27138bf80f4bSopenharmony_ci
27148bf80f4bSopenharmony_civoid SetAll(CORE_NS::Entity target, CORE_NS::Entity material, BASE_NS::vector<CORE_NS::Entity>& ret,
27158bf80f4bSopenharmony_ci    CORE3D_NS::IMeshComponentManager* meshComponentManager)
27168bf80f4bSopenharmony_ci{
27178bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(target)) {
27188bf80f4bSopenharmony_ci        if (auto handle = meshComponentManager->Write(target)) {
27198bf80f4bSopenharmony_ci            for (auto&& submesh : handle->submeshes) {
27208bf80f4bSopenharmony_ci                ret.push_back(submesh.material);
27218bf80f4bSopenharmony_ci                submesh.material = material;
27228bf80f4bSopenharmony_ci            }
27238bf80f4bSopenharmony_ci        }
27248bf80f4bSopenharmony_ci    }
27258bf80f4bSopenharmony_ci}
27268bf80f4bSopenharmony_ci
27278bf80f4bSopenharmony_civoid ResetAll(CORE_NS::Entity target, BASE_NS::vector<CORE_NS::Entity>& in,
27288bf80f4bSopenharmony_ci    CORE3D_NS::IMeshComponentManager* meshComponentManager)
27298bf80f4bSopenharmony_ci{
27308bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(target)) {
27318bf80f4bSopenharmony_ci        if (auto handle = meshComponentManager->Write(target)) {
27328bf80f4bSopenharmony_ci            for (auto&& submesh : handle->submeshes) {
27338bf80f4bSopenharmony_ci                if (in.size() > 0) {
27348bf80f4bSopenharmony_ci                    submesh.material = in.front();
27358bf80f4bSopenharmony_ci                    in.erase(in.begin());
27368bf80f4bSopenharmony_ci                }
27378bf80f4bSopenharmony_ci            }
27388bf80f4bSopenharmony_ci        }
27398bf80f4bSopenharmony_ci    }
27408bf80f4bSopenharmony_ci}
27418bf80f4bSopenharmony_ci
27428bf80f4bSopenharmony_ci// Set override material to multi-mesh
27438bf80f4bSopenharmony_ciBASE_NS::vector<CORE_NS::Entity> SceneHolder::SetOverrideMaterialMultimeshArray(
27448bf80f4bSopenharmony_ci    CORE_NS::Entity target, CORE_NS::Entity material)
27458bf80f4bSopenharmony_ci{
27468bf80f4bSopenharmony_ci    BASE_NS::vector<CORE_NS::Entity> ret;
27478bf80f4bSopenharmony_ci    if (ecs_) {
27488bf80f4bSopenharmony_ci        // if we contain render mesh handle, use it to set material
27498bf80f4bSopenharmony_ci        if (auto data = renderMeshComponentManager_->Read(target)) {
27508bf80f4bSopenharmony_ci            auto mesh = data->mesh;
27518bf80f4bSopenharmony_ci            SetAll(mesh, material, ret, meshComponentManager_);
27528bf80f4bSopenharmony_ci        }
27538bf80f4bSopenharmony_ci
27548bf80f4bSopenharmony_ci        // if our child contain meshes, update material on those
27558bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
27568bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
27578bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
27588bf80f4bSopenharmony_ci                    auto entity = child->GetEntity();
27598bf80f4bSopenharmony_ci                    if (auto data = renderMeshComponentManager_->Read(entity)) {
27608bf80f4bSopenharmony_ci                        auto mesh = data->mesh;
27618bf80f4bSopenharmony_ci                        SetAll(mesh, material, ret, meshComponentManager_);
27628bf80f4bSopenharmony_ci                    }
27638bf80f4bSopenharmony_ci                }
27648bf80f4bSopenharmony_ci            }
27658bf80f4bSopenharmony_ci        }
27668bf80f4bSopenharmony_ci    }
27678bf80f4bSopenharmony_ci    return ret;
27688bf80f4bSopenharmony_ci}
27698bf80f4bSopenharmony_ci
27708bf80f4bSopenharmony_ci// reset override material from multi-mesh
27718bf80f4bSopenharmony_civoid SceneHolder::ResetOverrideMaterialMultimeshArray(CORE_NS::Entity target, BASE_NS::vector<CORE_NS::Entity>& in)
27728bf80f4bSopenharmony_ci{
27738bf80f4bSopenharmony_ci    if (ecs_) {
27748bf80f4bSopenharmony_ci        BASE_NS::vector<CORE_NS::Entity> ret;
27758bf80f4bSopenharmony_ci
27768bf80f4bSopenharmony_ci        // if we contain render mesh handle, use it to set material
27778bf80f4bSopenharmony_ci        if (auto data = renderMeshComponentManager_->Read(target)) {
27788bf80f4bSopenharmony_ci            auto mesh = data->mesh;
27798bf80f4bSopenharmony_ci            ResetAll(mesh, in, meshComponentManager_);
27808bf80f4bSopenharmony_ci        }
27818bf80f4bSopenharmony_ci
27828bf80f4bSopenharmony_ci        // if our child contain meshes, update material on those
27838bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
27848bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
27858bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
27868bf80f4bSopenharmony_ci                    auto entity = child->GetEntity();
27878bf80f4bSopenharmony_ci                    if (auto data = renderMeshComponentManager_->Read(entity)) {
27888bf80f4bSopenharmony_ci                        auto mesh = data->mesh;
27898bf80f4bSopenharmony_ci                        ResetAll(mesh, in, meshComponentManager_);
27908bf80f4bSopenharmony_ci                    }
27918bf80f4bSopenharmony_ci                }
27928bf80f4bSopenharmony_ci            }
27938bf80f4bSopenharmony_ci        }
27948bf80f4bSopenharmony_ci    }
27958bf80f4bSopenharmony_ci    in.clear();
27968bf80f4bSopenharmony_ci}
27978bf80f4bSopenharmony_ci
27988bf80f4bSopenharmony_ci// Set instance count to multi-mesh
27998bf80f4bSopenharmony_civoid SceneHolder::SetInstanceCountMultimeshArray(CORE_NS::Entity target, size_t count)
28008bf80f4bSopenharmony_ci{
28018bf80f4bSopenharmony_ci    if (ecs_) {
28028bf80f4bSopenharmony_ci        if (auto parent = nodeSystem_->GetNode(target)) {
28038bf80f4bSopenharmony_ci            // this is kind of sub-optimization. If we have instances available, the mesh component is stored only
28048bf80f4bSopenharmony_ci            // in instances
28058bf80f4bSopenharmony_ci            CORE_NS::Entity firstBorn;
28068bf80f4bSopenharmony_ci            auto children = parent->GetChildren();
28078bf80f4bSopenharmony_ci
28088bf80f4bSopenharmony_ci            for (auto& child : children) {
28098bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
28108bf80f4bSopenharmony_ci                    firstBorn = child->GetEntity();
28118bf80f4bSopenharmony_ci                    break;
28128bf80f4bSopenharmony_ci                }
28138bf80f4bSopenharmony_ci            }
28148bf80f4bSopenharmony_ci
28158bf80f4bSopenharmony_ci            CORE3D_NS::MeshComponent meshData;
28168bf80f4bSopenharmony_ci
28178bf80f4bSopenharmony_ci            // when the instance count goes back to zero, we need to restore the data on parent
28188bf80f4bSopenharmony_ci            if (count == 0) {
28198bf80f4bSopenharmony_ci                if (CORE_NS::EntityUtil::IsValid(firstBorn)) {
28208bf80f4bSopenharmony_ci                    renderMeshComponentManager_->Create(target);
28218bf80f4bSopenharmony_ci                    if (auto renderMeshData = renderMeshComponentManager_->Write(target)) {
28228bf80f4bSopenharmony_ci                        if (auto instancingData = renderMeshComponentManager_->Read(firstBorn)) {
28238bf80f4bSopenharmony_ci                            *renderMeshData = *instancingData;
28248bf80f4bSopenharmony_ci                        }
28258bf80f4bSopenharmony_ci                    }
28268bf80f4bSopenharmony_ci                }
28278bf80f4bSopenharmony_ci                // now, when we move the templated item back to root, it will become visible by default
28288bf80f4bSopenharmony_ci            } else {
28298bf80f4bSopenharmony_ci                // if we have mesh, set things up using mesh
28308bf80f4bSopenharmony_ci                if (auto data = meshComponentManager_->Read(target)) {
28318bf80f4bSopenharmony_ci                    meshData = *data;
28328bf80f4bSopenharmony_ci                } else if (auto instanceData = renderMeshComponentManager_->Read(firstBorn)) {
28338bf80f4bSopenharmony_ci                    // otherwise we prefer the instanced data
28348bf80f4bSopenharmony_ci                    if (auto data = meshComponentManager_->Read(instanceData->mesh)) {
28358bf80f4bSopenharmony_ci                        // use instance data
28368bf80f4bSopenharmony_ci                        meshData = *data;
28378bf80f4bSopenharmony_ci                        // and switch target
28388bf80f4bSopenharmony_ci                        target = firstBorn;
28398bf80f4bSopenharmony_ci                    }
28408bf80f4bSopenharmony_ci                } else if (auto renderMeshData = renderMeshComponentManager_->Read(target)) {
28418bf80f4bSopenharmony_ci                    // and fallback to existing render mesh data if it exists
28428bf80f4bSopenharmony_ci                    if (auto data = meshComponentManager_->Read(renderMeshData->mesh)) {
28438bf80f4bSopenharmony_ci                        meshData = *data;
28448bf80f4bSopenharmony_ci                    }
28458bf80f4bSopenharmony_ci                }
28468bf80f4bSopenharmony_ci            }
28478bf80f4bSopenharmony_ci
28488bf80f4bSopenharmony_ci            size_t mmcount = 0;
28498bf80f4bSopenharmony_ci            for (auto& child : children) {
28508bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
28518bf80f4bSopenharmony_ci                    if (mmcount == count) {
28528bf80f4bSopenharmony_ci                        parent->RemoveChild(*child);
28538bf80f4bSopenharmony_ci                    } else {
28548bf80f4bSopenharmony_ci                        mmcount++;
28558bf80f4bSopenharmony_ci                    }
28568bf80f4bSopenharmony_ci                }
28578bf80f4bSopenharmony_ci            }
28588bf80f4bSopenharmony_ci
28598bf80f4bSopenharmony_ci            BASE_NS::vector<CORE_NS::Entity> clones;
28608bf80f4bSopenharmony_ci            while (mmcount < count) {
28618bf80f4bSopenharmony_ci                clones.push_back(ecs_->CloneEntity(target));
28628bf80f4bSopenharmony_ci                mmcount++;
28638bf80f4bSopenharmony_ci            }
28648bf80f4bSopenharmony_ci
28658bf80f4bSopenharmony_ci            for (auto clone : clones) {
28668bf80f4bSopenharmony_ci                // set up node system
28678bf80f4bSopenharmony_ci                auto node = nodeSystem_->GetNode(clone);
28688bf80f4bSopenharmony_ci                node->SetParent(*parent);
28698bf80f4bSopenharmony_ci                node->SetEnabled(true);
28708bf80f4bSopenharmony_ci                nameComponentManager_->Create(clone);
28718bf80f4bSopenharmony_ci
28728bf80f4bSopenharmony_ci                // set up name so we can identify cloned instances afterwards
28738bf80f4bSopenharmony_ci                if (auto nameHandle = nameComponentManager_->Write(clone)) {
28748bf80f4bSopenharmony_ci                    BASE_NS::string postFixed(MULTI_MESH_CHILD_PREFIX.data(), MULTI_MESH_CHILD_PREFIX.size());
28758bf80f4bSopenharmony_ci                    postFixed.append(BASE_NS::to_string(mmcount));
28768bf80f4bSopenharmony_ci                    nameHandle->name = postFixed;
28778bf80f4bSopenharmony_ci                }
28788bf80f4bSopenharmony_ci
28798bf80f4bSopenharmony_ci                // and finally mesh specifics
28808bf80f4bSopenharmony_ci                if (auto rmcHandle = renderMeshComponentManager_->Write(clone)) {
28818bf80f4bSopenharmony_ci                    // during the first clone, switch from template to first instance
28828bf80f4bSopenharmony_ci                    if (mmcount == 0) {
28838bf80f4bSopenharmony_ci                        renderMeshComponentManager_->Destroy(target);
28848bf80f4bSopenharmony_ci                        target = clone;
28858bf80f4bSopenharmony_ci                    }
28868bf80f4bSopenharmony_ci                    // Set batch
28878bf80f4bSopenharmony_ci                    rmcHandle->renderMeshBatch = target;
28888bf80f4bSopenharmony_ci                    // create new entity for mesh
28898bf80f4bSopenharmony_ci                    const CORE_NS::Entity entity = ecs_->GetEntityManager().Create();
28908bf80f4bSopenharmony_ci                    meshComponentManager_->Create(entity);
28918bf80f4bSopenharmony_ci                    // copy the data of the original
28928bf80f4bSopenharmony_ci                    *meshComponentManager_->Write(entity) = meshData;
28938bf80f4bSopenharmony_ci                    // and set the mesh to a new instance
28948bf80f4bSopenharmony_ci                    rmcHandle->mesh = entity;
28958bf80f4bSopenharmony_ci                }
28968bf80f4bSopenharmony_ci                mmcount++;
28978bf80f4bSopenharmony_ci            }
28988bf80f4bSopenharmony_ci            // Set up a batch
28998bf80f4bSopenharmony_ci            auto renderMeshBatchComponentManager =
29008bf80f4bSopenharmony_ci                CORE_NS::GetManager<CORE3D_NS::IRenderMeshBatchComponentManager>(*ecs_);
29018bf80f4bSopenharmony_ci            if (!renderMeshBatchComponentManager->HasComponent(firstBorn)) {
29028bf80f4bSopenharmony_ci                renderMeshBatchComponentManager->Create(firstBorn);
29038bf80f4bSopenharmony_ci            }
29048bf80f4bSopenharmony_ci            if (auto batchHandle = renderMeshBatchComponentManager->Write(firstBorn)) {
29058bf80f4bSopenharmony_ci                batchHandle->batchType = CORE3D_NS::RenderMeshBatchComponent::BatchType::GPU_INSTANCING;
29068bf80f4bSopenharmony_ci            }
29078bf80f4bSopenharmony_ci        }
29088bf80f4bSopenharmony_ci    }
29098bf80f4bSopenharmony_ci}
29108bf80f4bSopenharmony_ci
29118bf80f4bSopenharmony_ci// Set visible count to multi-mesh
29128bf80f4bSopenharmony_civoid SceneHolder::SetVisibleCountMultimeshArray(CORE_NS::Entity target, size_t count)
29138bf80f4bSopenharmony_ci{
29148bf80f4bSopenharmony_ci    if (ecs_) {
29158bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
29168bf80f4bSopenharmony_ci            size_t ix = 0;
29178bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
29188bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
29198bf80f4bSopenharmony_ci                    child->SetEnabled(ix < count);
29208bf80f4bSopenharmony_ci                    ix++;
29218bf80f4bSopenharmony_ci                }
29228bf80f4bSopenharmony_ci            }
29238bf80f4bSopenharmony_ci        }
29248bf80f4bSopenharmony_ci    }
29258bf80f4bSopenharmony_ci}
29268bf80f4bSopenharmony_ci
29278bf80f4bSopenharmony_ci// Set custom data to multi-mesh index
29288bf80f4bSopenharmony_civoid SceneHolder::SetCustomData(CORE_NS::Entity target, size_t index, const BASE_NS::Math::Vec4& data)
29298bf80f4bSopenharmony_ci{
29308bf80f4bSopenharmony_ci    if (ecs_) {
29318bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
29328bf80f4bSopenharmony_ci            size_t ix = 0;
29338bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
29348bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
29358bf80f4bSopenharmony_ci                    if (ix == index) {
29368bf80f4bSopenharmony_ci                        auto entity = child->GetEntity();
29378bf80f4bSopenharmony_ci                        if (auto handle = renderMeshComponentManager_->Write(entity)) {
29388bf80f4bSopenharmony_ci                            *static_cast<float*>(static_cast<void*>(&handle->customData[0].x)) = data.x;
29398bf80f4bSopenharmony_ci                            *static_cast<float*>(static_cast<void*>(&handle->customData[0].y)) = data.y;
29408bf80f4bSopenharmony_ci                            *static_cast<float*>(static_cast<void*>(&handle->customData[0].z)) = data.z;
29418bf80f4bSopenharmony_ci                            *static_cast<float*>(static_cast<void*>(&handle->customData[0].w)) = data.w;
29428bf80f4bSopenharmony_ci                        }
29438bf80f4bSopenharmony_ci                        return;
29448bf80f4bSopenharmony_ci                    }
29458bf80f4bSopenharmony_ci                    ix++;
29468bf80f4bSopenharmony_ci                }
29478bf80f4bSopenharmony_ci            }
29488bf80f4bSopenharmony_ci        }
29498bf80f4bSopenharmony_ci    }
29508bf80f4bSopenharmony_ci}
29518bf80f4bSopenharmony_ci
29528bf80f4bSopenharmony_ci// Set transformation to multi-mesh index
29538bf80f4bSopenharmony_civoid SceneHolder::SetTransformation(CORE_NS::Entity target, size_t index, const BASE_NS::Math::Mat4X4& transform)
29548bf80f4bSopenharmony_ci{
29558bf80f4bSopenharmony_ci    if (ecs_) {
29568bf80f4bSopenharmony_ci        if (const CORE3D_NS::ISceneNode* parent = nodeSystem_->GetNode(target)) {
29578bf80f4bSopenharmony_ci            size_t ix = 0;
29588bf80f4bSopenharmony_ci            for (auto& child : parent->GetChildren()) {
29598bf80f4bSopenharmony_ci                if (IsMultiMeshChild(child)) {
29608bf80f4bSopenharmony_ci                    if (ix == index) {
29618bf80f4bSopenharmony_ci                        auto entity = child->GetEntity();
29628bf80f4bSopenharmony_ci                        if (auto handle = transformComponentManager_->Write(entity)) {
29638bf80f4bSopenharmony_ci                            BASE_NS::Math::Quat rotation;
29648bf80f4bSopenharmony_ci                            BASE_NS::Math::Vec3 scale;
29658bf80f4bSopenharmony_ci                            BASE_NS::Math::Vec3 position;
29668bf80f4bSopenharmony_ci                            BASE_NS::Math::Vec3 skew;
29678bf80f4bSopenharmony_ci                            BASE_NS::Math::Vec4 persp;
29688bf80f4bSopenharmony_ci                            if (BASE_NS::Math::Decompose(transform, scale, rotation, position, skew, persp)) {
29698bf80f4bSopenharmony_ci                                handle->scale = scale;
29708bf80f4bSopenharmony_ci                                handle->rotation = rotation;
29718bf80f4bSopenharmony_ci                                handle->position = position;
29728bf80f4bSopenharmony_ci                            }
29738bf80f4bSopenharmony_ci                            return;
29748bf80f4bSopenharmony_ci                        }
29758bf80f4bSopenharmony_ci                    }
29768bf80f4bSopenharmony_ci                    ix++;
29778bf80f4bSopenharmony_ci                }
29788bf80f4bSopenharmony_ci            }
29798bf80f4bSopenharmony_ci        }
29808bf80f4bSopenharmony_ci    }
29818bf80f4bSopenharmony_ci}
29828bf80f4bSopenharmony_ci
29838bf80f4bSopenharmony_cibool SceneHolder::GetWorldMatrixComponentAABB(
29848bf80f4bSopenharmony_ci    SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity entity, bool isRecursive)
29858bf80f4bSopenharmony_ci{
29868bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
29878bf80f4bSopenharmony_ci        auto result = picking_->GetWorldMatrixComponentAABB(entity, isRecursive, *ecs_);
29888bf80f4bSopenharmony_ci        if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
29898bf80f4bSopenharmony_ci            writable->Add(result.minAABB);
29908bf80f4bSopenharmony_ci            writable->Add(result.maxAABB);
29918bf80f4bSopenharmony_ci            return true;
29928bf80f4bSopenharmony_ci        }
29938bf80f4bSopenharmony_ci    }
29948bf80f4bSopenharmony_ci    return false;
29958bf80f4bSopenharmony_ci}
29968bf80f4bSopenharmony_ci
29978bf80f4bSopenharmony_cibool SceneHolder::GetTransformComponentAABB(SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity entity, bool isRecursive)
29988bf80f4bSopenharmony_ci{
29998bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30008bf80f4bSopenharmony_ci        auto result = picking_->GetTransformComponentAABB(entity, isRecursive, *ecs_);
30018bf80f4bSopenharmony_ci        if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
30028bf80f4bSopenharmony_ci            writable->Add(result.minAABB);
30038bf80f4bSopenharmony_ci            writable->Add(result.maxAABB);
30048bf80f4bSopenharmony_ci            return true;
30058bf80f4bSopenharmony_ci        }
30068bf80f4bSopenharmony_ci    }
30078bf80f4bSopenharmony_ci    return false;
30088bf80f4bSopenharmony_ci}
30098bf80f4bSopenharmony_ci
30108bf80f4bSopenharmony_cibool SceneHolder::GetWorldAABB(SCENE_NS::IPickingResult::Ptr ret, const BASE_NS::Math::Mat4X4& world,
30118bf80f4bSopenharmony_ci    const BASE_NS::Math::Vec3& aabbMin, const BASE_NS::Math::Vec3& aabbMax)
30128bf80f4bSopenharmony_ci{
30138bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30148bf80f4bSopenharmony_ci        auto result = picking_->GetWorldAABB(world, aabbMin, aabbMax);
30158bf80f4bSopenharmony_ci        if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
30168bf80f4bSopenharmony_ci            writable->Add(result.minAABB);
30178bf80f4bSopenharmony_ci            writable->Add(result.maxAABB);
30188bf80f4bSopenharmony_ci            return true;
30198bf80f4bSopenharmony_ci        }
30208bf80f4bSopenharmony_ci    }
30218bf80f4bSopenharmony_ci    return false;
30228bf80f4bSopenharmony_ci}
30238bf80f4bSopenharmony_ci
30248bf80f4bSopenharmony_cibool ConvertToToolkit(const BASE_NS::vector<CORE3D_NS::RayCastResult>& result, SCENE_NS::IRayCastResult::Ptr ret)
30258bf80f4bSopenharmony_ci{
30268bf80f4bSopenharmony_ci    if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>(ret)) {
30278bf80f4bSopenharmony_ci        for (auto& value : result) {
30288bf80f4bSopenharmony_ci            BASE_NS::string path;
30298bf80f4bSopenharmony_ci            if (ResolveNodeFullPath(value.node, path)) {
30308bf80f4bSopenharmony_ci                writable->Add({ {}, value.distance });
30318bf80f4bSopenharmony_ci                writable->MetaData().push_back(path);
30328bf80f4bSopenharmony_ci            }
30338bf80f4bSopenharmony_ci        }
30348bf80f4bSopenharmony_ci        return true;
30358bf80f4bSopenharmony_ci    }
30368bf80f4bSopenharmony_ci    return false;
30378bf80f4bSopenharmony_ci}
30388bf80f4bSopenharmony_ci
30398bf80f4bSopenharmony_cibool SceneHolder::RayCast(
30408bf80f4bSopenharmony_ci    SCENE_NS::IRayCastResult::Ptr ret, const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction)
30418bf80f4bSopenharmony_ci{
30428bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30438bf80f4bSopenharmony_ci        auto result = picking_->RayCast(*ecs_, start, direction);
30448bf80f4bSopenharmony_ci        return ConvertToToolkit(result, ret);
30458bf80f4bSopenharmony_ci    }
30468bf80f4bSopenharmony_ci    return false;
30478bf80f4bSopenharmony_ci}
30488bf80f4bSopenharmony_ci
30498bf80f4bSopenharmony_cibool SceneHolder::RayCast(SCENE_NS::IRayCastResult::Ptr ret, const BASE_NS::Math::Vec3& start,
30508bf80f4bSopenharmony_ci    const BASE_NS::Math::Vec3& direction, uint64_t layerMask)
30518bf80f4bSopenharmony_ci{
30528bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30538bf80f4bSopenharmony_ci        auto result = picking_->RayCast(*ecs_, start, direction, layerMask);
30548bf80f4bSopenharmony_ci        return ConvertToToolkit(result, ret);
30558bf80f4bSopenharmony_ci    }
30568bf80f4bSopenharmony_ci    return false;
30578bf80f4bSopenharmony_ci}
30588bf80f4bSopenharmony_ci
30598bf80f4bSopenharmony_cibool SceneHolder::ScreenToWorld(
30608bf80f4bSopenharmony_ci    SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec3 screenCoordinate)
30618bf80f4bSopenharmony_ci{
30628bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30638bf80f4bSopenharmony_ci        auto result = picking_->ScreenToWorld(*ecs_, camera, screenCoordinate);
30648bf80f4bSopenharmony_ci        if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
30658bf80f4bSopenharmony_ci            writable->Add(result);
30668bf80f4bSopenharmony_ci            return true;
30678bf80f4bSopenharmony_ci        }
30688bf80f4bSopenharmony_ci    }
30698bf80f4bSopenharmony_ci    return false;
30708bf80f4bSopenharmony_ci}
30718bf80f4bSopenharmony_ci
30728bf80f4bSopenharmony_cibool SceneHolder::WorldToScreen(
30738bf80f4bSopenharmony_ci    SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec3 worldCoordinate)
30748bf80f4bSopenharmony_ci
30758bf80f4bSopenharmony_ci{
30768bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30778bf80f4bSopenharmony_ci        auto result = picking_->WorldToScreen(*ecs_, camera, worldCoordinate);
30788bf80f4bSopenharmony_ci        if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
30798bf80f4bSopenharmony_ci            writable->Add(result);
30808bf80f4bSopenharmony_ci            return true;
30818bf80f4bSopenharmony_ci        }
30828bf80f4bSopenharmony_ci    }
30838bf80f4bSopenharmony_ci    return false;
30848bf80f4bSopenharmony_ci}
30858bf80f4bSopenharmony_ci
30868bf80f4bSopenharmony_cibool SceneHolder::RayCastFromCamera(
30878bf80f4bSopenharmony_ci    SCENE_NS::IRayCastResult::Ptr ret, CORE_NS::Entity camera, const BASE_NS::Math::Vec2& screenPos)
30888bf80f4bSopenharmony_ci{
30898bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
30908bf80f4bSopenharmony_ci        auto result = picking_->RayCastFromCamera(*ecs_, camera, screenPos);
30918bf80f4bSopenharmony_ci        return ConvertToToolkit(result, ret);
30928bf80f4bSopenharmony_ci    }
30938bf80f4bSopenharmony_ci    return false;
30948bf80f4bSopenharmony_ci}
30958bf80f4bSopenharmony_ci
30968bf80f4bSopenharmony_cibool SceneHolder::RayCastFromCamera(
30978bf80f4bSopenharmony_ci    SCENE_NS::IRayCastResult::Ptr ret, CORE_NS::Entity camera, const BASE_NS::Math::Vec2& screenPos, uint64_t layerMask)
30988bf80f4bSopenharmony_ci{
30998bf80f4bSopenharmony_ci    if (picking_ && ecs_) {
31008bf80f4bSopenharmony_ci        auto result = picking_->RayCastFromCamera(*ecs_, camera, screenPos, layerMask);
31018bf80f4bSopenharmony_ci        return ConvertToToolkit(result, ret);
31028bf80f4bSopenharmony_ci    }
31038bf80f4bSopenharmony_ci    return false;
31048bf80f4bSopenharmony_ci}
31058bf80f4bSopenharmony_ci
31068bf80f4bSopenharmony_cibool SceneHolder::RayFromCamera(
31078bf80f4bSopenharmony_ci    SCENE_NS::IPickingResult::Ptr ret, CORE_NS::Entity camera, BASE_NS::Math::Vec2 screenCoordinate)
31088bf80f4bSopenharmony_ci{
31098bf80f4bSopenharmony_ci    if (auto cameraComponent = cameraComponentManager_->Read(camera)) {
31108bf80f4bSopenharmony_ci        if (auto worldMatrixManager = GetManager<CORE3D_NS::IWorldMatrixComponentManager>(*ecs_)) {
31118bf80f4bSopenharmony_ci            if (auto cameraWorldMatrixComponent = worldMatrixManager->Read(camera)) {
31128bf80f4bSopenharmony_ci                if (cameraComponent->projection == CORE3D_NS::CameraComponent::Projection::ORTHOGRAPHIC) {
31138bf80f4bSopenharmony_ci                    const auto worldPos = picking_->ScreenToWorld(
31148bf80f4bSopenharmony_ci                        *ecs_, camera, BASE_NS::Math::Vec3(screenCoordinate.x, screenCoordinate.y, 0.0f));
31158bf80f4bSopenharmony_ci                    const auto direction =
31168bf80f4bSopenharmony_ci                        cameraWorldMatrixComponent->matrix * BASE_NS::Math::Vec4(0.0f, 0.0f, -1.0f, 0.0f);
31178bf80f4bSopenharmony_ci                    if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
31188bf80f4bSopenharmony_ci                        writable->Add(worldPos);
31198bf80f4bSopenharmony_ci                        writable->Add(direction);
31208bf80f4bSopenharmony_ci                        return true;
31218bf80f4bSopenharmony_ci                    }
31228bf80f4bSopenharmony_ci                } else {
31238bf80f4bSopenharmony_ci                    // Ray origin is the camera world position.
31248bf80f4bSopenharmony_ci                    const auto rayOrigin = BASE_NS::Math::Vec3(cameraWorldMatrixComponent->matrix.w);
31258bf80f4bSopenharmony_ci                    const auto targetPos = picking_->ScreenToWorld(
31268bf80f4bSopenharmony_ci                        *ecs_, camera, BASE_NS::Math::Vec3(screenCoordinate.x, screenCoordinate.y, 1.0f));
31278bf80f4bSopenharmony_ci                    const auto direction = BASE_NS::Math::Normalize(targetPos - rayOrigin);
31288bf80f4bSopenharmony_ci                    if (auto writable = interface_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(ret)) {
31298bf80f4bSopenharmony_ci                        writable->Add(rayOrigin);
31308bf80f4bSopenharmony_ci                        writable->Add(direction);
31318bf80f4bSopenharmony_ci                        return true;
31328bf80f4bSopenharmony_ci                    }
31338bf80f4bSopenharmony_ci                }
31348bf80f4bSopenharmony_ci            }
31358bf80f4bSopenharmony_ci        }
31368bf80f4bSopenharmony_ci    }
31378bf80f4bSopenharmony_ci    return false;
31388bf80f4bSopenharmony_ci}
3139