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#include <algorithm> 168bf80f4bSopenharmony_ci#include <functional> 178bf80f4bSopenharmony_ci#include <scene_plugin/api/camera_uid.h> 188bf80f4bSopenharmony_ci#include <scene_plugin/api/environment_uid.h> 198bf80f4bSopenharmony_ci#include <scene_plugin/api/light_uid.h> 208bf80f4bSopenharmony_ci#include <scene_plugin/api/material_uid.h> 218bf80f4bSopenharmony_ci#include <scene_plugin/api/mesh_uid.h> 228bf80f4bSopenharmony_ci#include <scene_plugin/api/node_uid.h> 238bf80f4bSopenharmony_ci#include <scene_plugin/api/scene_uid.h> 248bf80f4bSopenharmony_ci#include <scene_plugin/api/view_node_uid.h> 258bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_ecs_scene.h> 268bf80f4bSopenharmony_ci#include <scene_plugin/interface/intf_environment.h> 278bf80f4bSopenharmony_ci 288bf80f4bSopenharmony_ci#include <3d/ecs/systems/intf_node_system.h> 298bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h> 308bf80f4bSopenharmony_ci 318bf80f4bSopenharmony_ci#include <meta/api/event_handler.h> 328bf80f4bSopenharmony_ci#include <meta/ext/object_container.h> 338bf80f4bSopenharmony_ci#include <meta/interface/animation/intf_animation_controller.h> 348bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h> 358bf80f4bSopenharmony_ci#include <meta/interface/intf_named.h> 368bf80f4bSopenharmony_ci#include <meta/interface/intf_object_hierarchy_observer.h> 378bf80f4bSopenharmony_ci#include <meta/interface/serialization/intf_importer.h> 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_ci#include "intf_node_private.h" 408bf80f4bSopenharmony_ci#include "intf_resource_private.h" 418bf80f4bSopenharmony_ci#include "scene_holder.h" 428bf80f4bSopenharmony_ci#include "task_utils.h" 438bf80f4bSopenharmony_ci 448bf80f4bSopenharmony_ci// "synchronously initialize the nodes from main scene file when the scene is loaded 458bf80f4bSopenharmony_ci 468bf80f4bSopenharmony_ci// Save the project .scene file when scene object is being serialized. In practice this may override the changes on 478bf80f4bSopenharmony_ci// scene file from other sources. To be rectified further 488bf80f4bSopenharmony_ci 498bf80f4bSopenharmony_ci// Name prefab instances with IObject::GetUid(). The other option is to use fixed "prefab_instance_NN" with running 508bf80f4bSopenharmony_ci// instance number. The latter may cause trouble with .scene-files if it contains previous instances 518bf80f4bSopenharmony_ci 528bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask; 538bf80f4bSopenharmony_cinamespace { 548bf80f4bSopenharmony_ciclass NotifyOnExit { 558bf80f4bSopenharmony_cipublic: 568bf80f4bSopenharmony_ci explicit NotifyOnExit(bool notify, std::function<void()> callback) : notify_(notify), callback_(callback) {} 578bf80f4bSopenharmony_ci virtual ~NotifyOnExit() 588bf80f4bSopenharmony_ci { 598bf80f4bSopenharmony_ci if (notify_) { 608bf80f4bSopenharmony_ci callback_(); 618bf80f4bSopenharmony_ci } 628bf80f4bSopenharmony_ci } 638bf80f4bSopenharmony_ci bool notify_; 648bf80f4bSopenharmony_ci std::function<void()> callback_; 658bf80f4bSopenharmony_ci}; 668bf80f4bSopenharmony_ci 678bf80f4bSopenharmony_ciclass SceneImpl final : public META_NS::ObjectContainerFwd<SceneImpl, SCENE_NS::ClassId::Scene, SCENE_NS::IScene, 688bf80f4bSopenharmony_ci SCENE_NS::IEcsScene, META_NS::IContent, META_NS::IAnimationController> { 698bf80f4bSopenharmony_ci /// Add the animation controller stuff here. (as scene should be the controller of it's animations) 708bf80f4bSopenharmony_ci META_FORWARD_READONLY_PROPERTY(uint32_t, Count, animationController_->Count()) 718bf80f4bSopenharmony_ci META_FORWARD_READONLY_PROPERTY(uint32_t, RunningCount, animationController_->RunningCount()) 728bf80f4bSopenharmony_ci 738bf80f4bSopenharmony_ci BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> GetAnimations() const override; 748bf80f4bSopenharmony_ci BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> GetRunning() const override; 758bf80f4bSopenharmony_ci bool AddAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) override; 768bf80f4bSopenharmony_ci bool RemoveAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) override; 778bf80f4bSopenharmony_ci void Clear() override; 788bf80f4bSopenharmony_ci StepInfo Step(const META_NS::IClock::ConstPtr& clock) override; 798bf80f4bSopenharmony_ci // now back to normal scene impl 808bf80f4bSopenharmony_ci 818bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(META_NS::INamed, BASE_NS::string, Name, {}) 828bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY( 838bf80f4bSopenharmony_ci SCENE_NS::IScene, BASE_NS::string, SystemGraphUri, "project://assets/config/system_graph.json") 848bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY( 858bf80f4bSopenharmony_ci SCENE_NS::IScene, uint32_t, Status, SCENE_STATUS_UNINITIALIZED, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 868bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IScene, SCENE_NS::INode::Ptr, RootNode, {}) 878bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, SCENE_NS::ICamera::Ptr, DefaultCamera, {}) 888bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, BASE_NS::string, Uri, {}) 898bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, bool, Asynchronous, false) 908bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IScene, SCENE_NS::IMaterial::Ptr, Materials, {}) 918bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, SCENE_NS::IRenderConfiguration::Ptr, RenderConfiguration, {}) 928bf80f4bSopenharmony_ci 938bf80f4bSopenharmony_ci META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnLoaded) 948bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IEcsScene, uint8_t, RenderMode, SCENE_NS::IEcsScene::RENDER_IF_DIRTY) 958bf80f4bSopenharmony_ci 968bf80f4bSopenharmony_ci META_FORWARD_READONLY_PROPERTY(IObject::Ptr, Content, (contentImpl_ ? contentImpl_->Content() : nullptr)) 978bf80f4bSopenharmony_ci META_FORWARD_PROPERTY(bool, ContentSearchable, (contentImpl_ ? contentImpl_->ContentSearchable() : nullptr)) 988bf80f4bSopenharmony_ci META_FORWARD_PROPERTY( 998bf80f4bSopenharmony_ci META_NS::IContentLoader::Ptr, ContentLoader, (contentImpl_ ? contentImpl_->ContentLoader() : nullptr)) 1008bf80f4bSopenharmony_ci 1018bf80f4bSopenharmony_ci void SetRenderMode() 1028bf80f4bSopenharmony_ci { 1038bf80f4bSopenharmony_ci AddEngineTask(MakeTask( 1048bf80f4bSopenharmony_ci [renderMode = META_NS::GetValue(RenderMode())](auto sceneHolder) { 1058bf80f4bSopenharmony_ci sceneHolder->SetRenderMode(renderMode); 1068bf80f4bSopenharmony_ci return false; 1078bf80f4bSopenharmony_ci }, 1088bf80f4bSopenharmony_ci sceneHolder_), 1098bf80f4bSopenharmony_ci false); 1108bf80f4bSopenharmony_ci } 1118bf80f4bSopenharmony_ci 1128bf80f4bSopenharmony_ci uint64_t GetCameraHandle(const SCENE_NS::ICamera::Ptr& camera) 1138bf80f4bSopenharmony_ci { 1148bf80f4bSopenharmony_ci if (camera) { 1158bf80f4bSopenharmony_ci auto ecsObject = interface_pointer_cast<SCENE_NS::IEcsObject>(camera); 1168bf80f4bSopenharmony_ci if (ecsObject) { 1178bf80f4bSopenharmony_ci return ecsObject->GetEntity().id; 1188bf80f4bSopenharmony_ci } 1198bf80f4bSopenharmony_ci } 1208bf80f4bSopenharmony_ci 1218bf80f4bSopenharmony_ci return SCENE_NS::IScene::DEFAULT_CAMERA; 1228bf80f4bSopenharmony_ci } 1238bf80f4bSopenharmony_ci 1248bf80f4bSopenharmony_ci struct BitmapInfo { 1258bf80f4bSopenharmony_ci BitmapInfo() = default; 1268bf80f4bSopenharmony_ci BitmapInfo(SCENE_NS::IBitmap::Ptr bmp) : bitmap(bmp) {} 1278bf80f4bSopenharmony_ci BASE_NS::Math::UVec2 size {}; 1288bf80f4bSopenharmony_ci SCENE_NS::IBitmap::Ptr bitmap {}; 1298bf80f4bSopenharmony_ci META_NS::EventHandler bitmapChanged {}; 1308bf80f4bSopenharmony_ci }; 1318bf80f4bSopenharmony_ci BASE_NS::unordered_map<uint64_t, BitmapInfo> bitmaps_; 1328bf80f4bSopenharmony_ci BitmapInfo& GetData(const SCENE_NS::ICamera::Ptr& camera) 1338bf80f4bSopenharmony_ci { 1348bf80f4bSopenharmony_ci auto cameraHandle = GetCameraHandle(camera); 1358bf80f4bSopenharmony_ci if (cameraHandle == SCENE_NS::IScene::DEFAULT_CAMERA) { 1368bf80f4bSopenharmony_ci cameraHandle = defaultCameraHandle_; 1378bf80f4bSopenharmony_ci } 1388bf80f4bSopenharmony_ci auto handle = cameraHandle; 1398bf80f4bSopenharmony_ci if (cameraHandle == SCENE_NS::IScene::DEFAULT_CAMERA && !bitmaps_.empty()) { 1408bf80f4bSopenharmony_ci handle = defaultCameraHandle_; 1418bf80f4bSopenharmony_ci } 1428bf80f4bSopenharmony_ci return bitmaps_[handle]; 1438bf80f4bSopenharmony_ci } 1448bf80f4bSopenharmony_ci 1458bf80f4bSopenharmony_ci void SetBitmap(const SCENE_NS::IBitmap::Ptr& bitmap, const SCENE_NS::ICamera::Ptr& camera) override 1468bf80f4bSopenharmony_ci { 1478bf80f4bSopenharmony_ci BitmapInfo& data = GetData(camera); 1488bf80f4bSopenharmony_ci auto uiBitmap = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap); 1498bf80f4bSopenharmony_ci if (!uiBitmap) { 1508bf80f4bSopenharmony_ci // disable bitmap override. 1518bf80f4bSopenharmony_ci data.bitmapChanged.Unsubscribe(); 1528bf80f4bSopenharmony_ci data.bitmap = {}; 1538bf80f4bSopenharmony_ci sceneHolder_->SetCameraTarget(camera, data.size, {}); 1548bf80f4bSopenharmony_ci return; 1558bf80f4bSopenharmony_ci } 1568bf80f4bSopenharmony_ci 1578bf80f4bSopenharmony_ci data.bitmap = uiBitmap; 1588bf80f4bSopenharmony_ci data.size = data.bitmap->Size()->GetValue(); 1598bf80f4bSopenharmony_ci const auto rh = data.bitmap->GetRenderHandle(); 1608bf80f4bSopenharmony_ci 1618bf80f4bSopenharmony_ci data.bitmapChanged.Subscribe( 1628bf80f4bSopenharmony_ci uiBitmap->ResourceChanged(), META_NS::MakeCallback<META_NS::IOnChanged>([this, camera]() { 1638bf80f4bSopenharmony_ci BitmapInfo& data = GetData(camera); 1648bf80f4bSopenharmony_ci data.size = data.bitmap->Size()->GetValue(); 1658bf80f4bSopenharmony_ci const auto rh = data.bitmap->GetRenderHandle(); 1668bf80f4bSopenharmony_ci sceneHolder_->SetCameraTarget(camera, data.size, rh); 1678bf80f4bSopenharmony_ci })); 1688bf80f4bSopenharmony_ci 1698bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(uiBitmap->ResourceChanged()); 1708bf80f4bSopenharmony_ci } 1718bf80f4bSopenharmony_ci 1728bf80f4bSopenharmony_ci SCENE_NS::IBitmap::Ptr GetBitmap(bool notifyFrameDrawn, const SCENE_NS::ICamera::Ptr& camera) override 1738bf80f4bSopenharmony_ci { 1748bf80f4bSopenharmony_ci BitmapInfo& data = GetData(camera); 1758bf80f4bSopenharmony_ci if (!data.bitmap) { 1768bf80f4bSopenharmony_ci // there is no bitmap for this. 1778bf80f4bSopenharmony_ci // create it? 1788bf80f4bSopenharmony_ci } 1798bf80f4bSopenharmony_ci return data.bitmap; 1808bf80f4bSopenharmony_ci } 1818bf80f4bSopenharmony_ci 1828bf80f4bSopenharmony_ci#define CREATE_META_INSTANCE(type, name) GetObjectRegistry().Create<META_NS::type>(META_NS::ClassId::name) 1838bf80f4bSopenharmony_ci 1848bf80f4bSopenharmony_ci // META_NS::IContent 1858bf80f4bSopenharmony_ci bool SetContent(const META_NS::IObject::Ptr& content) override 1868bf80f4bSopenharmony_ci { 1878bf80f4bSopenharmony_ci // Should be no-op because the Root Node of a scene (content in this case) can be assigned only if the scene was 1888bf80f4bSopenharmony_ci // reloaded. 1898bf80f4bSopenharmony_ci return false; 1908bf80f4bSopenharmony_ci } 1918bf80f4bSopenharmony_ci 1928bf80f4bSopenharmony_ci bool Build(const META_NS::IMetadata::Ptr& data) override 1938bf80f4bSopenharmony_ci { 1948bf80f4bSopenharmony_ci auto& registry = GetObjectRegistry(); 1958bf80f4bSopenharmony_ci 1968bf80f4bSopenharmony_ci animationController_ = registry.Create<META_NS::IAnimationController>(META_NS::ClassId::AnimationController); 1978bf80f4bSopenharmony_ci 1988bf80f4bSopenharmony_ci using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>; 1998bf80f4bSopenharmony_ci BASE_NS::shared_ptr<RENDER_NS::IRenderContext> rc; 2008bf80f4bSopenharmony_ci META_NS::ITaskQueue::Ptr appQueue; 2018bf80f4bSopenharmony_ci META_NS::ITaskQueue::Ptr engineQueue; 2028bf80f4bSopenharmony_ci 2038bf80f4bSopenharmony_ci if (data) { 2048bf80f4bSopenharmony_ci if (auto prp = data->GetPropertyByName<IntfPtr>("RenderContext")) { 2058bf80f4bSopenharmony_ci rc = interface_pointer_cast<RENDER_NS::IRenderContext>(prp->GetValue()); 2068bf80f4bSopenharmony_ci } 2078bf80f4bSopenharmony_ci if (auto prp = data->GetPropertyByName<IntfPtr>("EngineQueue")) { 2088bf80f4bSopenharmony_ci engineQueue = interface_pointer_cast<META_NS::ITaskQueue>(prp->GetValue()); 2098bf80f4bSopenharmony_ci } 2108bf80f4bSopenharmony_ci if (auto prp = data->GetPropertyByName<IntfPtr>("AppQueue")) { 2118bf80f4bSopenharmony_ci appQueue = interface_pointer_cast<META_NS::ITaskQueue>(prp->GetValue()); 2128bf80f4bSopenharmony_ci } 2138bf80f4bSopenharmony_ci } 2148bf80f4bSopenharmony_ci if ((!rc) || (!engineQueue) || (!appQueue)) { 2158bf80f4bSopenharmony_ci return false; 2168bf80f4bSopenharmony_ci } 2178bf80f4bSopenharmony_ci 2188bf80f4bSopenharmony_ci hierarchyController_ = 2198bf80f4bSopenharmony_ci registry.Create<META_NS::IObjectHierarchyObserver>(SCENE_NS::ClassId::NodeHierarchyController); 2208bf80f4bSopenharmony_ci 2218bf80f4bSopenharmony_ci contentImpl_ = registry.Create<META_NS::IContent>(META_NS::ClassId::ContentObject); 2228bf80f4bSopenharmony_ci if (const auto req = interface_cast<META_NS::IRequiredInterfaces>(contentImpl_)) { 2238bf80f4bSopenharmony_ci req->SetRequiredInterfaces({ SCENE_NS::INode::UID }); 2248bf80f4bSopenharmony_ci } 2258bf80f4bSopenharmony_ci 2268bf80f4bSopenharmony_ci sceneHolder_.reset(new SceneHolder(GetInstanceId(), registry, rc, appQueue, engineQueue)); 2278bf80f4bSopenharmony_ci sceneHolder_->SetOperationMode(Asynchronous()->GetValue()); 2288bf80f4bSopenharmony_ci 2298bf80f4bSopenharmony_ci asyncChangedToken_ = Asynchronous()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>( 2308bf80f4bSopenharmony_ci [](const auto& sceneHolder, const auto& async) { 2318bf80f4bSopenharmony_ci if (sceneHolder && async) { 2328bf80f4bSopenharmony_ci sceneHolder->SetOperationMode(async->GetValue()); 2338bf80f4bSopenharmony_ci } 2348bf80f4bSopenharmony_ci }, 2358bf80f4bSopenharmony_ci sceneHolder_, Asynchronous())); 2368bf80f4bSopenharmony_ci 2378bf80f4bSopenharmony_ci renderModeChangedToken_ = RenderMode()->OnChanged()->AddHandler( 2388bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() { 2398bf80f4bSopenharmony_ci if (auto self = static_pointer_cast<SceneImpl>(weak.lock())) { 2408bf80f4bSopenharmony_ci self->SetRenderMode(); 2418bf80f4bSopenharmony_ci } 2428bf80f4bSopenharmony_ci })); 2438bf80f4bSopenharmony_ci 2448bf80f4bSopenharmony_ci sceneHolder_->SetInitializeCallback( 2458bf80f4bSopenharmony_ci META_NS::MakeCallback<SceneHolder::ISceneInitialized>( 2468bf80f4bSopenharmony_ci [me = BASE_NS::weak_ptr(GetSelf())](const BASE_NS::string& rootId, const BASE_NS::string& cameraId) { 2478bf80f4bSopenharmony_ci if (auto self = me.lock().get()) 2488bf80f4bSopenharmony_ci static_cast<SceneImpl*>(self)->onSceneInitialized(rootId, cameraId); 2498bf80f4bSopenharmony_ci }), 2508bf80f4bSopenharmony_ci sceneHolder_); 2518bf80f4bSopenharmony_ci sceneHolder_->SetSceneLoadedCallback( 2528bf80f4bSopenharmony_ci META_NS::MakeCallback<SceneHolder::ISceneLoaded>([me = BASE_NS::weak_ptr(GetSelf())](uint32_t status) { 2538bf80f4bSopenharmony_ci if (auto self = me.lock().get()) 2548bf80f4bSopenharmony_ci static_cast<SceneImpl*>(self)->OnSceneLoaded(status); 2558bf80f4bSopenharmony_ci }), 2568bf80f4bSopenharmony_ci sceneHolder_); 2578bf80f4bSopenharmony_ci 2588bf80f4bSopenharmony_ci sceneHolder_->Initialize(sceneHolder_); 2598bf80f4bSopenharmony_ci sceneHolder_->SetSystemGraphUri(META_NS::GetValue(SystemGraphUri())); 2608bf80f4bSopenharmony_ci SubscribeToPropertyChanges(); 2618bf80f4bSopenharmony_ci 2628bf80f4bSopenharmony_ci return true; 2638bf80f4bSopenharmony_ci } 2648bf80f4bSopenharmony_ci 2658bf80f4bSopenharmony_ci // this is not usually needed as explicit action, but the scene will pickup changes from 2668bf80f4bSopenharmony_ci // ScenePresenters on the fly 2678bf80f4bSopenharmony_ci void OnCameraChanged() 2688bf80f4bSopenharmony_ci { 2698bf80f4bSopenharmony_ci // Async, sceneholder takes over 2708bf80f4bSopenharmony_ci if (sceneHolder_) { 2718bf80f4bSopenharmony_ci sceneHolder_->ChangeCamera(META_ACCESS_PROPERTY(DefaultCamera)->GetValue()); 2728bf80f4bSopenharmony_ci } 2738bf80f4bSopenharmony_ci } 2748bf80f4bSopenharmony_ci 2758bf80f4bSopenharmony_ci // Async, sceneholder takes over 2768bf80f4bSopenharmony_ci BASE_NS::vector<META_NS::IAnimation::Ptr> allAnims_; 2778bf80f4bSopenharmony_ci BASE_NS::vector<META_NS::IAnimation::Ptr> GetAnimations() override 2788bf80f4bSopenharmony_ci { 2798bf80f4bSopenharmony_ci // adds/removes animations to cache.. 2808bf80f4bSopenharmony_ci auto tmp = allAnims_; 2818bf80f4bSopenharmony_ci allAnims_.clear(); 2828bf80f4bSopenharmony_ci for (auto anim : sceneHolder_->GetAnimations()) { 2838bf80f4bSopenharmony_ci if (auto i = interface_cast<META_NS::IObject>(anim)) { 2848bf80f4bSopenharmony_ci auto name = i->GetName(); 2858bf80f4bSopenharmony_ci 2868bf80f4bSopenharmony_ci size_t ix = 0; 2878bf80f4bSopenharmony_ci if (!RollOverPrefix(ix, name, ANIMATIONS_PREFIX)) { 2888bf80f4bSopenharmony_ci continue; 2898bf80f4bSopenharmony_ci } 2908bf80f4bSopenharmony_ci 2918bf80f4bSopenharmony_ci // check cache 2928bf80f4bSopenharmony_ci META_NS::IAnimation::Ptr rn; 2938bf80f4bSopenharmony_ci auto subname = name.substr(ix); 2948bf80f4bSopenharmony_ci for (auto& a : tmp) { 2958bf80f4bSopenharmony_ci if (interface_cast<META_NS::IObject>(a)->GetName() == subname) { 2968bf80f4bSopenharmony_ci rn = a; 2978bf80f4bSopenharmony_ci break; 2988bf80f4bSopenharmony_ci } 2998bf80f4bSopenharmony_ci } 3008bf80f4bSopenharmony_ci if (!rn) { 3018bf80f4bSopenharmony_ci rn = interface_pointer_cast<META_NS::IAnimation>( 3028bf80f4bSopenharmony_ci CreateNode(name.substr(ix), false, SCENE_NS::ClassId::Animation.Id(), 3038bf80f4bSopenharmony_ci SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 3048bf80f4bSopenharmony_ci } 3058bf80f4bSopenharmony_ci 3068bf80f4bSopenharmony_ci allAnims_.push_back(rn); 3078bf80f4bSopenharmony_ci } 3088bf80f4bSopenharmony_ci } 3098bf80f4bSopenharmony_ci return allAnims_; 3108bf80f4bSopenharmony_ci } 3118bf80f4bSopenharmony_ci 3128bf80f4bSopenharmony_ci META_NS::IAnimation::Ptr GetAnimation(const BASE_NS::string_view name) override 3138bf80f4bSopenharmony_ci { 3148bf80f4bSopenharmony_ci#ifndef USE_DIRECT_ECS_ANIMATION 3158bf80f4bSopenharmony_ci 3168bf80f4bSopenharmony_ci size_t ix = 0; 3178bf80f4bSopenharmony_ci if (!RollOverPrefix(ix, name, ANIMATIONS_PREFIX)) { 3188bf80f4bSopenharmony_ci return { nullptr }; 3198bf80f4bSopenharmony_ci } 3208bf80f4bSopenharmony_ci 3218bf80f4bSopenharmony_ci // check cache 3228bf80f4bSopenharmony_ci if (auto it = animations_.find(name.substr(ix)); it != animations_.end()) { 3238bf80f4bSopenharmony_ci if (auto animation = it->second.lock()) { 3248bf80f4bSopenharmony_ci return animation; 3258bf80f4bSopenharmony_ci } 3268bf80f4bSopenharmony_ci } 3278bf80f4bSopenharmony_ci // Create EcsObject. When running asynchronously, we have no way of knowing if we can rely that existing 3288bf80f4bSopenharmony_ci // animation will be found 3298bf80f4bSopenharmony_ci auto anim = interface_pointer_cast<META_NS::IAnimation>(CreateNode(name.substr(ix), false, 3308bf80f4bSopenharmony_ci SCENE_NS::ClassId::Animation.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 3318bf80f4bSopenharmony_ci 3328bf80f4bSopenharmony_ci return anim; 3338bf80f4bSopenharmony_ci#else 3348bf80f4bSopenharmony_ci auto ecsAnimation = sceneHolder_->GetAnimation(BASE_NS::string(name.data(), name.size())); 3358bf80f4bSopenharmony_ci 3368bf80f4bSopenharmony_ci if (!ecsAnimation) { 3378bf80f4bSopenharmony_ci ecsAnimation = GetObjectRegistry().Create<SCENE_NS::IEcsAnimation>(SCENE_NS::ClassId::EcsAnimation); 3388bf80f4bSopenharmony_ci AddEngineTask( 3398bf80f4bSopenharmony_ci META_NS::MakeCallable<META_NS::ITaskQueueTask>( 3408bf80f4bSopenharmony_ci [ecsAnimation, nameString = BASE_NS::string(name.data(), name.size()), 3418bf80f4bSopenharmony_ci weak = BASE_NS::weak_ptr(sceneHolder_)]() { 3428bf80f4bSopenharmony_ci if (auto sceneHolder = weak.lock()) { 3438bf80f4bSopenharmony_ci CORE_NS::Entity entity; 3448bf80f4bSopenharmony_ci if (sceneHolder->FindAnimation(nameString, entity)) { 3458bf80f4bSopenharmony_ci if (auto ecsProxyIf = interface_pointer_cast<SCENE_NS::IEcsProxyObject>(ecsAnimation)) { 3468bf80f4bSopenharmony_ci ecsProxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener()); 3478bf80f4bSopenharmony_ci } 3488bf80f4bSopenharmony_ci ecsAnimation->SetEntity(*sceneHolder->GetEcs(), entity); 3498bf80f4bSopenharmony_ci } 3508bf80f4bSopenharmony_ci } 3518bf80f4bSopenharmony_ci return false; 3528bf80f4bSopenharmony_ci }), 3538bf80f4bSopenharmony_ci false); 3548bf80f4bSopenharmony_ci } 3558bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Animations)->Get()->Add(ecsAnimation); 3568bf80f4bSopenharmony_ci 3578bf80f4bSopenharmony_ci return interface_pointer_cast<META_NS::IAnimation>(ecsAnimation); 3588bf80f4bSopenharmony_ci#endif 3598bf80f4bSopenharmony_ci } 3608bf80f4bSopenharmony_ci 3618bf80f4bSopenharmony_ci void CreateEmpty() override 3628bf80f4bSopenharmony_ci { 3638bf80f4bSopenharmony_ci Load("scene://empty"); 3648bf80f4bSopenharmony_ci } 3658bf80f4bSopenharmony_ci 3668bf80f4bSopenharmony_ci bool Load(const BASE_NS::string_view uri) override 3678bf80f4bSopenharmony_ci { 3688bf80f4bSopenharmony_ci if (!Name()->IsValueSet()) { 3698bf80f4bSopenharmony_ci SetValue(Name(), "Scene"); 3708bf80f4bSopenharmony_ci } 3718bf80f4bSopenharmony_ci 3728bf80f4bSopenharmony_ci if (!uri.empty()) { 3738bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_LOADING); 3748bf80f4bSopenharmony_ci sceneHolder_->Load(BASE_NS::string(uri.data(), uri.size())); 3758bf80f4bSopenharmony_ci return true; 3768bf80f4bSopenharmony_ci } 3778bf80f4bSopenharmony_ci return false; 3788bf80f4bSopenharmony_ci } 3798bf80f4bSopenharmony_ci 3808bf80f4bSopenharmony_ci void onSystemGraphUriChanged() 3818bf80f4bSopenharmony_ci { 3828bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_LOADING); 3838bf80f4bSopenharmony_ci sceneHolder_->SetSystemGraphUri(META_NS::GetValue(SystemGraphUri())); 3848bf80f4bSopenharmony_ci } 3858bf80f4bSopenharmony_ci 3868bf80f4bSopenharmony_ci void SetRenderSize(uint32_t width, uint32_t height, const SCENE_NS::ICamera::Ptr& camera) override 3878bf80f4bSopenharmony_ci { 3888bf80f4bSopenharmony_ci if (camera) { 3898bf80f4bSopenharmony_ci camera->SetDefaultRenderTargetSize(width, height); 3908bf80f4bSopenharmony_ci } else if (auto defaultCamera = META_NS::GetValue(DefaultCamera())) { 3918bf80f4bSopenharmony_ci defaultCamera->SetDefaultRenderTargetSize(width, height); 3928bf80f4bSopenharmony_ci } 3938bf80f4bSopenharmony_ci } 3948bf80f4bSopenharmony_ci 3958bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr GetNode(const BASE_NS::string_view path, const BASE_NS::Uid classId, 3968bf80f4bSopenharmony_ci SCENE_NS::INode::BuildBehavior buildBehavior) override 3978bf80f4bSopenharmony_ci { 3988bf80f4bSopenharmony_ci return GetNodeRecursive(path, classId, true, buildBehavior); 3998bf80f4bSopenharmony_ci } 4008bf80f4bSopenharmony_ci 4018bf80f4bSopenharmony_ci META_NS::ObjectId ResolveNodeTypeFromPath(const BASE_NS::string_view patchedPath, bool isNodeType) 4028bf80f4bSopenharmony_ci { 4038bf80f4bSopenharmony_ci // This is best effort 4048bf80f4bSopenharmony_ci // We cannot determine the type unless ECS has probed the component 4058bf80f4bSopenharmony_ci 4068bf80f4bSopenharmony_ci // This kind of introspection may cause materials and meshes to be treated as nodes 4078bf80f4bSopenharmony_ci // which kind of contradicts with their normal use through API 4088bf80f4bSopenharmony_ci auto ecs = GetEcs(); 4098bf80f4bSopenharmony_ci CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*ecs); 4108bf80f4bSopenharmony_ci const auto& root = nodeSystem.GetRootNode(); 4118bf80f4bSopenharmony_ci 4128bf80f4bSopenharmony_ci const auto& ecsNode = root.LookupNodeByPath(patchedPath); 4138bf80f4bSopenharmony_ci CORE_NS::Entity entity {}; 4148bf80f4bSopenharmony_ci if (ecsNode) { 4158bf80f4bSopenharmony_ci entity = ecsNode->GetEntity(); 4168bf80f4bSopenharmony_ci } else { 4178bf80f4bSopenharmony_ci CORE_LOG_W("%s:No entity for %s, type info not available", __func__, BASE_NS::string(patchedPath).c_str()); 4188bf80f4bSopenharmony_ci CORE_LOG_W("If you know the expected type, consider using a template or providing the class id"); 4198bf80f4bSopenharmony_ci } 4208bf80f4bSopenharmony_ci 4218bf80f4bSopenharmony_ci // shadow camera could provide false positive, so order matters 4228bf80f4bSopenharmony_ci if (auto lightManager = ecs->GetComponentManager(CORE3D_NS::ILightComponentManager::UID)) { 4238bf80f4bSopenharmony_ci if (lightManager->HasComponent(entity)) { 4248bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Light; 4258bf80f4bSopenharmony_ci } 4268bf80f4bSopenharmony_ci } 4278bf80f4bSopenharmony_ci 4288bf80f4bSopenharmony_ci if (auto cameraManager = ecs->GetComponentManager(CORE3D_NS::ICameraComponentManager::UID)) { 4298bf80f4bSopenharmony_ci if (cameraManager->HasComponent(entity)) { 4308bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Camera; 4318bf80f4bSopenharmony_ci } 4328bf80f4bSopenharmony_ci } 4338bf80f4bSopenharmony_ci 4348bf80f4bSopenharmony_ci if (auto envManager = ecs->GetComponentManager(CORE3D_NS::IEnvironmentComponentManager::UID)) { 4358bf80f4bSopenharmony_ci if (envManager->HasComponent(entity)) { 4368bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Environment; 4378bf80f4bSopenharmony_ci } 4388bf80f4bSopenharmony_ci } 4398bf80f4bSopenharmony_ci 4408bf80f4bSopenharmony_ci if (!isNodeType) { 4418bf80f4bSopenharmony_ci if (auto nodeManager = ecs->GetComponentManager(CORE3D_NS::INodeComponentManager::UID)) { 4428bf80f4bSopenharmony_ci // quirk, prefer nodes with node component treated as node) 4438bf80f4bSopenharmony_ci if (!nodeManager->HasComponent(entity)) { 4448bf80f4bSopenharmony_ci if (auto meshManager = ecs->GetComponentManager(CORE3D_NS::IMeshComponentManager::UID)) { 4458bf80f4bSopenharmony_ci if (meshManager->HasComponent(entity)) { 4468bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Mesh; 4478bf80f4bSopenharmony_ci } 4488bf80f4bSopenharmony_ci } 4498bf80f4bSopenharmony_ci if (auto materialManager = ecs->GetComponentManager(CORE3D_NS::IMaterialComponentManager::UID)) { 4508bf80f4bSopenharmony_ci if (materialManager->HasComponent(entity)) { 4518bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Material; 4528bf80f4bSopenharmony_ci } 4538bf80f4bSopenharmony_ci } 4548bf80f4bSopenharmony_ci } 4558bf80f4bSopenharmony_ci } 4568bf80f4bSopenharmony_ci } 4578bf80f4bSopenharmony_ci 4588bf80f4bSopenharmony_ci return SCENE_NS::ClassId::Node; 4598bf80f4bSopenharmony_ci } 4608bf80f4bSopenharmony_ci 4618bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr GetNodeRecursive(const BASE_NS::string_view path, const META_NS::ObjectId classId, 4628bf80f4bSopenharmony_ci bool recurse, SCENE_NS::INode::BuildBehavior buildBehavior) 4638bf80f4bSopenharmony_ci { 4648bf80f4bSopenharmony_ci if (path.empty() || path == "/") { 4658bf80f4bSopenharmony_ci return SCENE_NS::INode::Ptr {}; 4668bf80f4bSopenharmony_ci } 4678bf80f4bSopenharmony_ci 4688bf80f4bSopenharmony_ci BASE_NS::string patchedPath = recurse ? NormalizePath(path) : BASE_NS::string(path.data(), path.size()); 4698bf80f4bSopenharmony_ci if (auto ite = nodes_.find(patchedPath) != nodes_.cend()) { 4708bf80f4bSopenharmony_ci return nodes_[patchedPath]; 4718bf80f4bSopenharmony_ci } 4728bf80f4bSopenharmony_ci 4738bf80f4bSopenharmony_ci // ensure parent objects exist 4748bf80f4bSopenharmony_ci if (recurse) { 4758bf80f4bSopenharmony_ci size_t ix = patchedPath.find('/', 1); 4768bf80f4bSopenharmony_ci while (BASE_NS::string_view::npos != ix) { 4778bf80f4bSopenharmony_ci auto substr = patchedPath.substr(0, ix); 4788bf80f4bSopenharmony_ci // When we traverse up the tree, we must ensure that the object is a node. 4798bf80f4bSopenharmony_ci currentParent_ = GetNodeRecursive(substr, SCENE_NS::INode::UID, false, buildBehavior); 4808bf80f4bSopenharmony_ci ++ix; 4818bf80f4bSopenharmony_ci ix = patchedPath.find('/', ix); 4828bf80f4bSopenharmony_ci } 4838bf80f4bSopenharmony_ci } 4848bf80f4bSopenharmony_ci 4858bf80f4bSopenharmony_ci auto ecs = GetEcs(); 4868bf80f4bSopenharmony_ci META_NS::ObjectId implementationId = SCENE_NS::ClassId::Node; 4878bf80f4bSopenharmony_ci 4888bf80f4bSopenharmony_ci bool isNodeType = (classId == SCENE_NS::INode::UID); 4898bf80f4bSopenharmony_ci if ((classId == META_NS::IObject::UID || isNodeType) && ecs) { 4908bf80f4bSopenharmony_ci implementationId = ResolveNodeTypeFromPath(patchedPath, isNodeType); 4918bf80f4bSopenharmony_ci 4928bf80f4bSopenharmony_ci } else { 4938bf80f4bSopenharmony_ci implementationId = classId; 4948bf80f4bSopenharmony_ci } 4958bf80f4bSopenharmony_ci 4968bf80f4bSopenharmony_ci auto node = CreateNode(patchedPath, false, implementationId, buildBehavior); 4978bf80f4bSopenharmony_ci 4988bf80f4bSopenharmony_ci currentParent_ = {}; 4998bf80f4bSopenharmony_ci return node; // finalInterface; 5008bf80f4bSopenharmony_ci } 5018bf80f4bSopenharmony_ci 5028bf80f4bSopenharmony_ci void RemoveNodeFromCurrentContainer(SCENE_NS::INode::Ptr& node) 5038bf80f4bSopenharmony_ci { 5048bf80f4bSopenharmony_ci if (auto containable = interface_cast<META_NS::IContainable>(node)) { 5058bf80f4bSopenharmony_ci if (auto parent = interface_pointer_cast<META_NS::IContainer>(containable->GetParent())) { 5068bf80f4bSopenharmony_ci parent->Remove(node); 5078bf80f4bSopenharmony_ci } 5088bf80f4bSopenharmony_ci } 5098bf80f4bSopenharmony_ci } 5108bf80f4bSopenharmony_ci 5118bf80f4bSopenharmony_ci bool RollOverPrefix(size_t& ix, const BASE_NS::string_view& name, const BASE_NS::string_view& prefix) 5128bf80f4bSopenharmony_ci { 5138bf80f4bSopenharmony_ci while (ix < name.length() && name[ix] == '/') { 5148bf80f4bSopenharmony_ci ix++; 5158bf80f4bSopenharmony_ci } 5168bf80f4bSopenharmony_ci 5178bf80f4bSopenharmony_ci if (name.substr(ix).find(prefix) == 0) { 5188bf80f4bSopenharmony_ci ix += prefix.length(); 5198bf80f4bSopenharmony_ci } 5208bf80f4bSopenharmony_ci 5218bf80f4bSopenharmony_ci while (ix < name.length() && name[ix] == '/') { 5228bf80f4bSopenharmony_ci ix++; 5238bf80f4bSopenharmony_ci } 5248bf80f4bSopenharmony_ci 5258bf80f4bSopenharmony_ci return ix < name.length(); 5268bf80f4bSopenharmony_ci } 5278bf80f4bSopenharmony_ci 5288bf80f4bSopenharmony_ci void AddMaterial(SCENE_NS::IMaterial::Ptr material) override 5298bf80f4bSopenharmony_ci { 5308bf80f4bSopenharmony_ci auto materials = Materials()->GetValue(); 5318bf80f4bSopenharmony_ci auto it = std::find(materials.begin(), materials.end(), material); 5328bf80f4bSopenharmony_ci if (it != materials.end()) { 5338bf80f4bSopenharmony_ci // Already exists. 5348bf80f4bSopenharmony_ci CORE_LOG_D("Trying to add same material to scene multiple times."); 5358bf80f4bSopenharmony_ci return; 5368bf80f4bSopenharmony_ci } 5378bf80f4bSopenharmony_ci 5388bf80f4bSopenharmony_ci Materials()->AddValue(material); 5398bf80f4bSopenharmony_ci UpdateCachedReference(interface_pointer_cast<SCENE_NS::INode>(material)); 5408bf80f4bSopenharmony_ci } 5418bf80f4bSopenharmony_ci 5428bf80f4bSopenharmony_ci void RemoveMaterial(SCENE_NS::IMaterial::Ptr material) override 5438bf80f4bSopenharmony_ci { 5448bf80f4bSopenharmony_ci auto lock = Materials().GetLockedAccess(); 5458bf80f4bSopenharmony_ci auto vec = lock->GetValue(); 5468bf80f4bSopenharmony_ci for (size_t index = 0; index != vec.size(); ++index) { 5478bf80f4bSopenharmony_ci if (vec[index] == material) { 5488bf80f4bSopenharmony_ci lock->RemoveAt(index); 5498bf80f4bSopenharmony_ci break; 5508bf80f4bSopenharmony_ci } 5518bf80f4bSopenharmony_ci } 5528bf80f4bSopenharmony_ci 5538bf80f4bSopenharmony_ci for (auto&& ite : materials_) { 5548bf80f4bSopenharmony_ci if (ite.second.lock() == material) { 5558bf80f4bSopenharmony_ci ReleaseMaterial(ite.first); 5568bf80f4bSopenharmony_ci break; 5578bf80f4bSopenharmony_ci } 5588bf80f4bSopenharmony_ci } 5598bf80f4bSopenharmony_ci } 5608bf80f4bSopenharmony_ci 5618bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::ICamera::Ptr> GetCameras() const override 5628bf80f4bSopenharmony_ci { 5638bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::ICamera::Ptr> result; 5648bf80f4bSopenharmony_ci for (auto c : cameras_) { 5658bf80f4bSopenharmony_ci if (auto cam = c.second.lock()) { 5668bf80f4bSopenharmony_ci result.push_back(cam); 5678bf80f4bSopenharmony_ci } 5688bf80f4bSopenharmony_ci } 5698bf80f4bSopenharmony_ci return result; 5708bf80f4bSopenharmony_ci } 5718bf80f4bSopenharmony_ci 5728bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::IMaterial::Ptr> GetMaterials() const override 5738bf80f4bSopenharmony_ci { 5748bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::IMaterial::Ptr> result; 5758bf80f4bSopenharmony_ci for (auto& material : materials_) { 5768bf80f4bSopenharmony_ci auto ptr = material.second.lock(); 5778bf80f4bSopenharmony_ci if (ptr) { 5788bf80f4bSopenharmony_ci result.push_back(ptr); 5798bf80f4bSopenharmony_ci } 5808bf80f4bSopenharmony_ci } 5818bf80f4bSopenharmony_ci 5828bf80f4bSopenharmony_ci return result; 5838bf80f4bSopenharmony_ci } 5848bf80f4bSopenharmony_ci 5858bf80f4bSopenharmony_ci // Returns a material from the scene with a given path 5868bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr GetMaterial(const BASE_NS::string_view name) override 5878bf80f4bSopenharmony_ci { 5888bf80f4bSopenharmony_ci // The material file, aka uri-path is somewhat parallel due ownership is different for uri-materials 5898bf80f4bSopenharmony_ci // however, one can claim traditional handle and have them preserved 5908bf80f4bSopenharmony_ci // through flat cache. Should be consolidated someday. 5918bf80f4bSopenharmony_ci if (name.find("://") != BASE_NS::string_view::npos) { 5928bf80f4bSopenharmony_ci return GetOrLoadMaterial(name); 5938bf80f4bSopenharmony_ci } 5948bf80f4bSopenharmony_ci 5958bf80f4bSopenharmony_ci size_t ix = 0; 5968bf80f4bSopenharmony_ci if (!RollOverPrefix(ix, name, MATERIALS_PREFIX)) { 5978bf80f4bSopenharmony_ci return { nullptr }; 5988bf80f4bSopenharmony_ci } 5998bf80f4bSopenharmony_ci 6008bf80f4bSopenharmony_ci // check cache (first with name:entityid) 6018bf80f4bSopenharmony_ci if (auto it = materials_.find(name.substr(ix)); it != materials_.end()) { 6028bf80f4bSopenharmony_ci if (auto material = it->second.lock()) { 6038bf80f4bSopenharmony_ci return material; 6048bf80f4bSopenharmony_ci } 6058bf80f4bSopenharmony_ci } 6068bf80f4bSopenharmony_ci 6078bf80f4bSopenharmony_ci // check cache (direct material name) 6088bf80f4bSopenharmony_ci for (auto entry : materials_) { 6098bf80f4bSopenharmony_ci auto material = entry.second.lock(); 6108bf80f4bSopenharmony_ci if (auto node = interface_pointer_cast<SCENE_NS::INode>(material)) { 6118bf80f4bSopenharmony_ci if (node->Name()->GetValue() == name) { 6128bf80f4bSopenharmony_ci return material; 6138bf80f4bSopenharmony_ci } 6148bf80f4bSopenharmony_ci } 6158bf80f4bSopenharmony_ci } 6168bf80f4bSopenharmony_ci 6178bf80f4bSopenharmony_ci if (auto it = materials_.find(name.substr(ix)); it != materials_.end()) { 6188bf80f4bSopenharmony_ci if (auto material = it->second.lock()) { 6198bf80f4bSopenharmony_ci return material; 6208bf80f4bSopenharmony_ci } 6218bf80f4bSopenharmony_ci } 6228bf80f4bSopenharmony_ci 6238bf80f4bSopenharmony_ci // Create EcsObject. When running asynchronously, we have no way of knowing if we should create 6248bf80f4bSopenharmony_ci // new node or just rely that existing will be found 6258bf80f4bSopenharmony_ci auto mat = interface_pointer_cast<SCENE_NS::IMaterial>(CreateNode(name.substr(ix), false, 6268bf80f4bSopenharmony_ci SCENE_NS::ClassId::Material.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 6278bf80f4bSopenharmony_ci 6288bf80f4bSopenharmony_ci return mat; 6298bf80f4bSopenharmony_ci } 6308bf80f4bSopenharmony_ci 6318bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::IMesh::Ptr> GetMeshes() const override 6328bf80f4bSopenharmony_ci { 6338bf80f4bSopenharmony_ci BASE_NS::vector<SCENE_NS::IMesh::Ptr> result; 6348bf80f4bSopenharmony_ci for (auto mesh : meshes_) { 6358bf80f4bSopenharmony_ci auto ptr = mesh.second.lock(); 6368bf80f4bSopenharmony_ci if (ptr) { 6378bf80f4bSopenharmony_ci result.push_back(ptr); 6388bf80f4bSopenharmony_ci } 6398bf80f4bSopenharmony_ci } 6408bf80f4bSopenharmony_ci 6418bf80f4bSopenharmony_ci return result; 6428bf80f4bSopenharmony_ci } 6438bf80f4bSopenharmony_ci 6448bf80f4bSopenharmony_ci // Returns a material from the scene with a given name 6458bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr GetMesh(const BASE_NS::string_view name) override 6468bf80f4bSopenharmony_ci { 6478bf80f4bSopenharmony_ci size_t ix = 0; 6488bf80f4bSopenharmony_ci if (!RollOverPrefix(ix, name, MESHES_PREFIX)) { 6498bf80f4bSopenharmony_ci return { nullptr }; 6508bf80f4bSopenharmony_ci } 6518bf80f4bSopenharmony_ci 6528bf80f4bSopenharmony_ci // check cache 6538bf80f4bSopenharmony_ci if (auto it = meshes_.find(name.substr(ix)); it != meshes_.end()) { 6548bf80f4bSopenharmony_ci if (auto mesh = it->second.lock()) { 6558bf80f4bSopenharmony_ci return mesh; 6568bf80f4bSopenharmony_ci } 6578bf80f4bSopenharmony_ci } 6588bf80f4bSopenharmony_ci // Create EcsObject. When running asynchronously, we have no way of knowing if we should create 6598bf80f4bSopenharmony_ci // new node or just rely that existing will be found 6608bf80f4bSopenharmony_ci auto mesh = interface_pointer_cast<SCENE_NS::IMesh>(CreateNode(name.substr(ix), false, 6618bf80f4bSopenharmony_ci SCENE_NS::ClassId::Mesh.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 6628bf80f4bSopenharmony_ci 6638bf80f4bSopenharmony_ci return mesh; 6648bf80f4bSopenharmony_ci } 6658bf80f4bSopenharmony_ci 6668bf80f4bSopenharmony_ci BASE_NS::string constructPath(CORE_NS::Entity ent) const 6678bf80f4bSopenharmony_ci { 6688bf80f4bSopenharmony_ci auto ecs = GetEcs(); 6698bf80f4bSopenharmony_ci auto* nodeManager = CORE_NS::GetManager<CORE3D_NS::INodeComponentManager>(*ecs); 6708bf80f4bSopenharmony_ci auto* nameManager = CORE_NS::GetManager<CORE3D_NS::INameComponentManager>(*ecs); 6718bf80f4bSopenharmony_ci BASE_NS::string path; 6728bf80f4bSopenharmony_ci if (nodeManager && nameManager) { 6738bf80f4bSopenharmony_ci auto curent = ent; 6748bf80f4bSopenharmony_ci for (;;) { 6758bf80f4bSopenharmony_ci if (!CORE_NS::EntityUtil::IsValid(curent)) { 6768bf80f4bSopenharmony_ci // Reached root. 6778bf80f4bSopenharmony_ci break; 6788bf80f4bSopenharmony_ci } 6798bf80f4bSopenharmony_ci if (!nodeManager->HasComponent(curent)) { 6808bf80f4bSopenharmony_ci // not a node? 6818bf80f4bSopenharmony_ci return ""; 6828bf80f4bSopenharmony_ci } 6838bf80f4bSopenharmony_ci if (!nameManager->HasComponent(curent)) { 6848bf80f4bSopenharmony_ci // no name in hierarchy. "fail"? or generate "name" for path.. 6858bf80f4bSopenharmony_ci return ""; 6868bf80f4bSopenharmony_ci } 6878bf80f4bSopenharmony_ci auto namecomp = nameManager->Get(curent); 6888bf80f4bSopenharmony_ci if (!path.empty()) { 6898bf80f4bSopenharmony_ci path.insert(0, "/"); 6908bf80f4bSopenharmony_ci } 6918bf80f4bSopenharmony_ci path.insert(0, namecomp.name.c_str()); 6928bf80f4bSopenharmony_ci const auto& node = nodeManager->Get(curent); 6938bf80f4bSopenharmony_ci curent = node.parent; 6948bf80f4bSopenharmony_ci } 6958bf80f4bSopenharmony_ci } 6968bf80f4bSopenharmony_ci if (!path.empty()) { 6978bf80f4bSopenharmony_ci path.insert(0, "/"); 6988bf80f4bSopenharmony_ci } 6998bf80f4bSopenharmony_ci return path; 7008bf80f4bSopenharmony_ci } 7018bf80f4bSopenharmony_ci // Implementation for scene change callbacks. 7028bf80f4bSopenharmony_ci // The tricky bit here is that we may have placeholders on containers that may have received serialized data 7038bf80f4bSopenharmony_ci // during construction, so we just cannot replace those, but need to rebind them instead 7048bf80f4bSopenharmony_ci void onSceneInitialized(const BASE_NS::string& rootId, const BASE_NS::string& cameraId) 7058bf80f4bSopenharmony_ci { 7068bf80f4bSopenharmony_ci // Set root node 7078bf80f4bSopenharmony_ci rootNodeId_ = rootId; 7088bf80f4bSopenharmony_ci auto rootIdNormalized = NormalizePath(rootNodeId_); 7098bf80f4bSopenharmony_ci 7108bf80f4bSopenharmony_ci if (rootNodePtr_) { 7118bf80f4bSopenharmony_ci // check if someone assigned us a root node while we are preserving the previous one 7128bf80f4bSopenharmony_ci if (!META_ACCESS_PROPERTY(RootNode)->GetValue()) { 7138bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(RootNode)->SetValue(rootNodePtr_); 7148bf80f4bSopenharmony_ci } 7158bf80f4bSopenharmony_ci rootNodePtr_.reset(); 7168bf80f4bSopenharmony_ci } 7178bf80f4bSopenharmony_ci 7188bf80f4bSopenharmony_ci if (cameraNodePtr_) { 7198bf80f4bSopenharmony_ci // check if someone assigned us a root node while we are preserving the previous one 7208bf80f4bSopenharmony_ci if (!META_ACCESS_PROPERTY(DefaultCamera)->GetValue()) { 7218bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(DefaultCamera)->SetValue(cameraNodePtr_); 7228bf80f4bSopenharmony_ci } 7238bf80f4bSopenharmony_ci cameraNodePtr_.reset(); 7248bf80f4bSopenharmony_ci } 7258bf80f4bSopenharmony_ci 7268bf80f4bSopenharmony_ci if (auto renderConfiguration = META_NS::GetValue(RenderConfiguration())) { 7278bf80f4bSopenharmony_ci // Ensure the render configuration is bound to scene. 7288bf80f4bSopenharmony_ci auto resource = interface_pointer_cast<IResourcePrivate>(renderConfiguration); 7298bf80f4bSopenharmony_ci if (resource) { 7308bf80f4bSopenharmony_ci resource->Connect(sceneHolder_); 7318bf80f4bSopenharmony_ci } 7328bf80f4bSopenharmony_ci } 7338bf80f4bSopenharmony_ci 7348bf80f4bSopenharmony_ci // setup subscription for toolkit changes 7358bf80f4bSopenharmony_ci RenderConfiguration()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() { 7368bf80f4bSopenharmony_ci auto resource = interface_pointer_cast<IResourcePrivate>(GetValue(RenderConfiguration())); 7378bf80f4bSopenharmony_ci if (resource) { 7388bf80f4bSopenharmony_ci resource->Connect(sceneHolder_); 7398bf80f4bSopenharmony_ci } 7408bf80f4bSopenharmony_ci }), 7418bf80f4bSopenharmony_ci reinterpret_cast<uint64_t>(this)); 7428bf80f4bSopenharmony_ci 7438bf80f4bSopenharmony_ci if (auto rootNode = META_ACCESS_PROPERTY(RootNode)->GetValue()) { 7448bf80f4bSopenharmony_ci // switch new ecsObject 7458bf80f4bSopenharmony_ci BindNodeToEcs(rootNode, rootIdNormalized, false); 7468bf80f4bSopenharmony_ci nodes_[rootIdNormalized] = rootNode; 7478bf80f4bSopenharmony_ci } else { 7488bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(RootNode)->SetValue(GetSelf<SCENE_NS::IScene>()->GetNode<SCENE_NS::INode>(rootId)); 7498bf80f4bSopenharmony_ci } 7508bf80f4bSopenharmony_ci 7518bf80f4bSopenharmony_ci auto defaultCamera = META_ACCESS_PROPERTY(DefaultCamera)->GetValue(); 7528bf80f4bSopenharmony_ci if (!defaultCamera) { 7538bf80f4bSopenharmony_ci defaultCamera = GetSelf<SCENE_NS::IScene>()->GetNode<SCENE_NS::ICamera>(cameraId); 7548bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(DefaultCamera)->SetValue(defaultCamera); 7558bf80f4bSopenharmony_ci } 7568bf80f4bSopenharmony_ci 7578bf80f4bSopenharmony_ci if (defaultCamera) { 7588bf80f4bSopenharmony_ci ActivateCamera(defaultCamera); 7598bf80f4bSopenharmony_ci } 7608bf80f4bSopenharmony_ci 7618bf80f4bSopenharmony_ci // under normal conditions, this would take place asyncronously 7628bf80f4bSopenharmony_ci // however, if we are running on synchronous mode we need to restore the ecs bindings here 7638bf80f4bSopenharmony_ci for (auto& prevNode : nodes_) { 7648bf80f4bSopenharmony_ci if (prevNode.first != rootIdNormalized && prevNode.first != cameraId) { 7658bf80f4bSopenharmony_ci BindNodeToEcs(prevNode.second, prevNode.first, false); 7668bf80f4bSopenharmony_ci } 7678bf80f4bSopenharmony_ci } 7688bf80f4bSopenharmony_ci 7698bf80f4bSopenharmony_ci // This is information only unless we instantiate all the scene nodes immediately 7708bf80f4bSopenharmony_ci // Should be flagged more effectively on production builds 7718bf80f4bSopenharmony_ci CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*GetEcs()); 7728bf80f4bSopenharmony_ci const auto& root = nodeSystem.GetRootNode(); 7738bf80f4bSopenharmony_ci 7748bf80f4bSopenharmony_ci instantiateNodes(root, "/"); 7758bf80f4bSopenharmony_ci 7768bf80f4bSopenharmony_ci // notify observers about the change 7778bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Status)->SetValue(SCENE_NS::IScene::SCENE_STATUS_READY); 7788bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnLoaded()); 7798bf80f4bSopenharmony_ci 7808bf80f4bSopenharmony_ci sceneHolder_->SetUninitializeCallback( 7818bf80f4bSopenharmony_ci META_NS::MakeCallback<SceneHolder::ISceneUninitialized>([me = BASE_NS::weak_ptr(GetSelf())]() { 7828bf80f4bSopenharmony_ci if (auto self = me.lock().get()) 7838bf80f4bSopenharmony_ci static_cast<SceneImpl*>(self)->DetachScene(); 7848bf80f4bSopenharmony_ci }), 7858bf80f4bSopenharmony_ci sceneHolder_); 7868bf80f4bSopenharmony_ci } 7878bf80f4bSopenharmony_ci 7888bf80f4bSopenharmony_ci void OnSceneLoaded(uint32_t status) 7898bf80f4bSopenharmony_ci { 7908bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Status)->SetValue(status); 7918bf80f4bSopenharmony_ci if (status == SCENE_NS::IScene::SCENE_STATUS_READY) { 7928bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnLoaded()); 7938bf80f4bSopenharmony_ci } 7948bf80f4bSopenharmony_ci } 7958bf80f4bSopenharmony_ci 7968bf80f4bSopenharmony_ci // Implementation for scene processing. 7978bf80f4bSopenharmony_ci 7988bf80f4bSopenharmony_ci void DetachScene(bool setDirty = false) 7998bf80f4bSopenharmony_ci { 8008bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY(Status)) { 8018bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_UNINITIALIZED); 8028bf80f4bSopenharmony_ci } 8038bf80f4bSopenharmony_ci 8048bf80f4bSopenharmony_ci cameras_.clear(); 8058bf80f4bSopenharmony_ci materials_.clear(); 8068bf80f4bSopenharmony_ci meshes_.clear(); 8078bf80f4bSopenharmony_ci animations_.clear(); 8088bf80f4bSopenharmony_ci nodes_.clear(); 8098bf80f4bSopenharmony_ci 8108bf80f4bSopenharmony_ci // This effectively means that we keep the scene user objects forcibly live 8118bf80f4bSopenharmony_ci // until we get fresh ones to replace them, not sure if that is intended 8128bf80f4bSopenharmony_ci rootNodePtr_ = META_ACCESS_PROPERTY(RootNode)->GetValue(); 8138bf80f4bSopenharmony_ci cameraNodePtr_ = META_ACCESS_PROPERTY(DefaultCamera)->GetValue(); 8148bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(RootNode)->SetValue({}); 8158bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(DefaultCamera)->SetValue({}); 8168bf80f4bSopenharmony_ci 8178bf80f4bSopenharmony_ci if (setDirty) { 8188bf80f4bSopenharmony_ci for (const auto& bitmap : bitmaps_) { 8198bf80f4bSopenharmony_ci /*auto externalBitmap = interface_pointer_cast<UI_NS::ILume2DExternalBitmap>(bitmap.second.bitmap); 8208bf80f4bSopenharmony_ci if (externalBitmap) { 8218bf80f4bSopenharmony_ci externalBitmap->SetCoreBitmap(nullptr); 8228bf80f4bSopenharmony_ci }*/ 8238bf80f4bSopenharmony_ci bitmap.second.bitmap->SetRenderHandle({}, { 0, 0 }); 8248bf80f4bSopenharmony_ci } 8258bf80f4bSopenharmony_ci } 8268bf80f4bSopenharmony_ci } 8278bf80f4bSopenharmony_ci 8288bf80f4bSopenharmony_ci void instantiateNodes(const CORE3D_NS::ISceneNode& node, BASE_NS::string path) 8298bf80f4bSopenharmony_ci { 8308bf80f4bSopenharmony_ci if (!path.empty() && path.back() != '/') { 8318bf80f4bSopenharmony_ci path.append("/"); 8328bf80f4bSopenharmony_ci } 8338bf80f4bSopenharmony_ci if (!node.GetName().empty()) { 8348bf80f4bSopenharmony_ci path.append(node.GetName()); 8358bf80f4bSopenharmony_ci } else { 8368bf80f4bSopenharmony_ci#ifndef INSTANTIATE_NODES_ON_INITIALIZE 8378bf80f4bSopenharmony_ci path.append("["); 8388bf80f4bSopenharmony_ci path.append(BASE_NS::to_string(node.GetEntity().id)); 8398bf80f4bSopenharmony_ci path.append("]"); 8408bf80f4bSopenharmony_ci#endif 8418bf80f4bSopenharmony_ci } 8428bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("%s", path.c_str()); 8438bf80f4bSopenharmony_ci#ifdef INSTANTIATE_NODES_ON_INITIALIZE 8448bf80f4bSopenharmony_ci GetNode(path); 8458bf80f4bSopenharmony_ci#endif 8468bf80f4bSopenharmony_ci 8478bf80f4bSopenharmony_ci for (const auto child : node.GetChildren()) 8488bf80f4bSopenharmony_ci instantiateNodes(*child, path); 8498bf80f4bSopenharmony_ci } 8508bf80f4bSopenharmony_ci 8518bf80f4bSopenharmony_ci BASE_NS::string NormalizePath(const BASE_NS::string_view& path) 8528bf80f4bSopenharmony_ci { 8538bf80f4bSopenharmony_ci BASE_NS::string patchedPath; 8548bf80f4bSopenharmony_ci if (path == rootNodeId_) { 8558bf80f4bSopenharmony_ci patchedPath = path; 8568bf80f4bSopenharmony_ci patchedPath.insert(0, "/"); 8578bf80f4bSopenharmony_ci } else { 8588bf80f4bSopenharmony_ci bool hasSlash = (path[0] == '/'); 8598bf80f4bSopenharmony_ci if (path.compare(hasSlash ? 1 : 0, rootNodeId_.size(), rootNodeId_.data())) { 8608bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("%s: the path does not contain root node, patching the path", __func__); 8618bf80f4bSopenharmony_ci patchedPath.append("/"); 8628bf80f4bSopenharmony_ci patchedPath.append(rootNodeId_); 8638bf80f4bSopenharmony_ci if (!hasSlash) { 8648bf80f4bSopenharmony_ci patchedPath.append("/"); 8658bf80f4bSopenharmony_ci } 8668bf80f4bSopenharmony_ci patchedPath.append(path.data(), path.size()); 8678bf80f4bSopenharmony_ci } else { 8688bf80f4bSopenharmony_ci patchedPath = path; 8698bf80f4bSopenharmony_ci if (!hasSlash) { 8708bf80f4bSopenharmony_ci patchedPath = "/" + patchedPath; 8718bf80f4bSopenharmony_ci } 8728bf80f4bSopenharmony_ci } 8738bf80f4bSopenharmony_ci } 8748bf80f4bSopenharmony_ci return patchedPath; 8758bf80f4bSopenharmony_ci } 8768bf80f4bSopenharmony_ci 8778bf80f4bSopenharmony_ci SCENE_NS::IEcsObject::Ptr FindEcsObject(const BASE_NS::string_view& path, BASE_NS::string& patchedPath) 8788bf80f4bSopenharmony_ci { 8798bf80f4bSopenharmony_ci patchedPath = NormalizePath(path); 8808bf80f4bSopenharmony_ci 8818bf80f4bSopenharmony_ci if (auto it = nodes_.find(patchedPath); it != nodes_.end()) { 8828bf80f4bSopenharmony_ci return interface_pointer_cast<SCENE_NS::IEcsObject>(it->second); 8838bf80f4bSopenharmony_ci } 8848bf80f4bSopenharmony_ci return SCENE_NS::IEcsObject::Ptr {}; 8858bf80f4bSopenharmony_ci } 8868bf80f4bSopenharmony_ci 8878bf80f4bSopenharmony_ci SCENE_NS::IEcsObject::Ptr CreateNewEcsObject(const BASE_NS::string& /*path*/) 8888bf80f4bSopenharmony_ci { 8898bf80f4bSopenharmony_ci // Create new helper object 8908bf80f4bSopenharmony_ci // Not much left here, could be presumably removed 8918bf80f4bSopenharmony_ci auto ret = SCENE_NS::IEcsObject::Ptr {}; 8928bf80f4bSopenharmony_ci 8938bf80f4bSopenharmony_ci// Allow construction to progress even ecs was not available, 8948bf80f4bSopenharmony_ci// nodes will perform initialization asynchronously anyway 8958bf80f4bSopenharmony_ci if (auto object = META_NS::GetObjectRegistry().Create(SCENE_NS::ClassId::EcsObject)) { 8968bf80f4bSopenharmony_ci ret = interface_pointer_cast<SCENE_NS::IEcsObject>(object); 8978bf80f4bSopenharmony_ci } 8988bf80f4bSopenharmony_ci return ret; 8998bf80f4bSopenharmony_ci } 9008bf80f4bSopenharmony_ci 9018bf80f4bSopenharmony_ci SCENE_NS::IEcsObject::Ptr GetEcsObject(const BASE_NS::string_view& path) override 9028bf80f4bSopenharmony_ci { 9038bf80f4bSopenharmony_ci return interface_pointer_cast<SCENE_NS::IEcsObject>( 9048bf80f4bSopenharmony_ci GetNode(path, META_NS::IObject::UID, SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 9058bf80f4bSopenharmony_ci } 9068bf80f4bSopenharmony_ci 9078bf80f4bSopenharmony_ci CORE_NS::IEcs::Ptr GetEcs() override 9088bf80f4bSopenharmony_ci { 9098bf80f4bSopenharmony_ci return sceneHolder_->GetEcs(); 9108bf80f4bSopenharmony_ci } 9118bf80f4bSopenharmony_ci 9128bf80f4bSopenharmony_ci CORE_NS::IEcs::Ptr GetEcs() const 9138bf80f4bSopenharmony_ci { 9148bf80f4bSopenharmony_ci return sceneHolder_->GetEcs(); 9158bf80f4bSopenharmony_ci } 9168bf80f4bSopenharmony_ci 9178bf80f4bSopenharmony_ci META_NS::ITaskQueue::Token AddEngineTask( 9188bf80f4bSopenharmony_ci const META_NS::ITaskQueue::CallableType::Ptr& task, bool runDeferred) override 9198bf80f4bSopenharmony_ci { 9208bf80f4bSopenharmony_ci if (sceneHolder_) { 9218bf80f4bSopenharmony_ci return sceneHolder_->QueueEngineTask(task, runDeferred); 9228bf80f4bSopenharmony_ci } 9238bf80f4bSopenharmony_ci return META_NS::ITaskQueue::Token {}; 9248bf80f4bSopenharmony_ci } 9258bf80f4bSopenharmony_ci 9268bf80f4bSopenharmony_ci META_NS::ITaskQueue::Token AddApplicationTask( 9278bf80f4bSopenharmony_ci const META_NS::ITaskQueue::CallableType::Ptr& task, bool runDeferred) override 9288bf80f4bSopenharmony_ci { 9298bf80f4bSopenharmony_ci if (sceneHolder_) { 9308bf80f4bSopenharmony_ci return sceneHolder_->QueueApplicationTask(task, runDeferred); 9318bf80f4bSopenharmony_ci } 9328bf80f4bSopenharmony_ci return META_NS::ITaskQueue::Token {}; 9338bf80f4bSopenharmony_ci } 9348bf80f4bSopenharmony_ci 9358bf80f4bSopenharmony_ci void CancelEngineTask(META_NS::ITaskQueue::Token token) override 9368bf80f4bSopenharmony_ci { 9378bf80f4bSopenharmony_ci if (sceneHolder_) { 9388bf80f4bSopenharmony_ci return sceneHolder_->CancelEngineTask(token); 9398bf80f4bSopenharmony_ci } 9408bf80f4bSopenharmony_ci } 9418bf80f4bSopenharmony_ci 9428bf80f4bSopenharmony_ci void CancelAppTask(META_NS::ITaskQueue::Token token) override 9438bf80f4bSopenharmony_ci { 9448bf80f4bSopenharmony_ci if (sceneHolder_) { 9458bf80f4bSopenharmony_ci return sceneHolder_->CancelAppTask(token); 9468bf80f4bSopenharmony_ci } 9478bf80f4bSopenharmony_ci } 9488bf80f4bSopenharmony_ci 9498bf80f4bSopenharmony_ci SCENE_NS::IEntityCollection* GetEntityCollection() override 9508bf80f4bSopenharmony_ci { 9518bf80f4bSopenharmony_ci if (sceneHolder_) { 9528bf80f4bSopenharmony_ci return sceneHolder_->GetEntityCollection(); 9538bf80f4bSopenharmony_ci } 9548bf80f4bSopenharmony_ci 9558bf80f4bSopenharmony_ci return {}; 9568bf80f4bSopenharmony_ci } 9578bf80f4bSopenharmony_ci 9588bf80f4bSopenharmony_ci SCENE_NS::IAssetManager* GetAssetManager() override 9598bf80f4bSopenharmony_ci { 9608bf80f4bSopenharmony_ci if (sceneHolder_) { 9618bf80f4bSopenharmony_ci return sceneHolder_->GetAssetManager(); 9628bf80f4bSopenharmony_ci } 9638bf80f4bSopenharmony_ci 9648bf80f4bSopenharmony_ci return {}; 9658bf80f4bSopenharmony_ci } 9668bf80f4bSopenharmony_ci 9678bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr GetOrLoadMaterial(BASE_NS::string_view uri) 9688bf80f4bSopenharmony_ci { 9698bf80f4bSopenharmony_ci // check cache 9708bf80f4bSopenharmony_ci if (auto it = uriMaterials_.find(uri); it != uriMaterials_.end()) { 9718bf80f4bSopenharmony_ci if (auto material = it->second.lock()) { 9728bf80f4bSopenharmony_ci return material; 9738bf80f4bSopenharmony_ci } 9748bf80f4bSopenharmony_ci } 9758bf80f4bSopenharmony_ci 9768bf80f4bSopenharmony_ci auto ret = LoadMaterial(uri); 9778bf80f4bSopenharmony_ci uriMaterials_[uri] = ret; 9788bf80f4bSopenharmony_ci return ret; 9798bf80f4bSopenharmony_ci } 9808bf80f4bSopenharmony_ci 9818bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr LoadMaterial(BASE_NS::string_view uri) override 9828bf80f4bSopenharmony_ci { 9838bf80f4bSopenharmony_ci bool isGltfUri = (uri.find(".glb/materials/") != BASE_NS::string_view::npos) || 9848bf80f4bSopenharmony_ci (uri.find(".gltf/materials/") != BASE_NS::string_view::npos); 9858bf80f4bSopenharmony_ci if (isGltfUri) { 9868bf80f4bSopenharmony_ci auto resource = CreateResourceFromUri(SCENE_NS::ClassId::Material, uri); 9878bf80f4bSopenharmony_ci if (resource) { 9888bf80f4bSopenharmony_ci return interface_pointer_cast<SCENE_NS::IMaterial>(resource); 9898bf80f4bSopenharmony_ci } 9908bf80f4bSopenharmony_ci 9918bf80f4bSopenharmony_ci CORE_LOG_W("Could not resolve material URI: %s", BASE_NS::string(uri.data(), uri.size()).c_str()); 9928bf80f4bSopenharmony_ci // we could return the control to CreateMaterial and let the engine resolve the materials with uri 9938bf80f4bSopenharmony_ci // componenta as they seem to be in place when loaded from glb or gltf 9948bf80f4bSopenharmony_ci } 9958bf80f4bSopenharmony_ci 9968bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr ret; 9978bf80f4bSopenharmony_ci 9988bf80f4bSopenharmony_ci return ret; 9998bf80f4bSopenharmony_ci } 10008bf80f4bSopenharmony_ci 10018bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr CreateNode(const META_NS::ObjectId classId) 10028bf80f4bSopenharmony_ci { 10038bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr node; 10048bf80f4bSopenharmony_ci 10058bf80f4bSopenharmony_ci if (classId == SCENE_NS::ClassId::Light.Id() || classId == SCENE_NS::ILight::UID) { 10068bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Light); 10078bf80f4bSopenharmony_ci } else if (classId == SCENE_NS::ClassId::Camera.Id() || classId == SCENE_NS::ICamera::UID) { 10088bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Camera); 10098bf80f4bSopenharmony_ci } /*else if (classId == SCENE_NS::ClassId::ViewNode.Id() || classId == SCENE_NS::IViewNode::UID) { 10108bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::ViewNode); 10118bf80f4bSopenharmony_ci } */ 10128bf80f4bSopenharmony_ci else if (classId == SCENE_NS::ClassId::Material.Id() || classId == SCENE_NS::IMaterial::UID) { 10138bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Material); 10148bf80f4bSopenharmony_ci } else if (classId == SCENE_NS::ClassId::Mesh.Id() || classId == SCENE_NS::IMesh::UID) { 10158bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Mesh); 10168bf80f4bSopenharmony_ci } else if (classId == SCENE_NS::ClassId::Animation.Id() || classId == META_NS::IAnimation::UID) { 10178bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Animation); 10188bf80f4bSopenharmony_ci } else if (classId == SCENE_NS::ClassId::Environment.Id() || classId == SCENE_NS::IEnvironment::UID) { 10198bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Environment); 10208bf80f4bSopenharmony_ci } else { 10218bf80f4bSopenharmony_ci if (classId != META_NS::IObject::UID && classId != SCENE_NS::ClassId::Node.Id() && 10228bf80f4bSopenharmony_ci classId != SCENE_NS::INode::UID) { 10238bf80f4bSopenharmony_ci CORE_LOG_W("%s: uid not known, returning INode instance", __func__); 10248bf80f4bSopenharmony_ci } 10258bf80f4bSopenharmony_ci 10268bf80f4bSopenharmony_ci node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Node); 10278bf80f4bSopenharmony_ci } 10288bf80f4bSopenharmony_ci 10298bf80f4bSopenharmony_ci return node; 10308bf80f4bSopenharmony_ci } 10318bf80f4bSopenharmony_ci 10328bf80f4bSopenharmony_ci // Quirk / constraints: 10338bf80f4bSopenharmony_ci // 1) has name -> cached and asynchronously initialized 10348bf80f4bSopenharmony_ci // 2) name empty, just an object, not sure if needed at the end 10358bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr CreateNode(const BASE_NS::string_view name, bool createEngineObject, 10368bf80f4bSopenharmony_ci const META_NS::ObjectId classId, SCENE_NS::INode::BuildBehavior buildBehavior) override 10378bf80f4bSopenharmony_ci { 10388bf80f4bSopenharmony_ci if (const auto& ite = nodes_.find(name); ite != nodes_.cend() && createEngineObject) { 10398bf80f4bSopenharmony_ci CORE_LOG_W("Refusing to create new duplicate node: %s", BASE_NS::string(name.data(), name.size()).c_str()); 10408bf80f4bSopenharmony_ci return ite->second; 10418bf80f4bSopenharmony_ci } 10428bf80f4bSopenharmony_ci 10438bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr node = CreateNode(classId); 10448bf80f4bSopenharmony_ci 10458bf80f4bSopenharmony_ci if (node) { 10468bf80f4bSopenharmony_ci node->BuildChildren(buildBehavior); 10478bf80f4bSopenharmony_ci BindNodeToEcs(node, name, createEngineObject); 10488bf80f4bSopenharmony_ci } 10498bf80f4bSopenharmony_ci return node; 10508bf80f4bSopenharmony_ci } 10518bf80f4bSopenharmony_ci 10528bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr CreateResourceFromUri(const META_NS::ObjectId classId, BASE_NS::string_view uri) 10538bf80f4bSopenharmony_ci { 10548bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr node; 10558bf80f4bSopenharmony_ci 10568bf80f4bSopenharmony_ci auto entity = sceneHolder_->GetEntityByUri(uri); 10578bf80f4bSopenharmony_ci 10588bf80f4bSopenharmony_ci if (CORE_NS::EntityUtil::IsValid(entity)) { 10598bf80f4bSopenharmony_ci BASE_NS::string name; 10608bf80f4bSopenharmony_ci if (sceneHolder_->GetEntityName(entity, name)) { 10618bf80f4bSopenharmony_ci node = CreateNode(classId); 10628bf80f4bSopenharmony_ci if (node) { 10638bf80f4bSopenharmony_ci auto ecsScene = GetSelf<SCENE_NS::IEcsScene>(); 10648bf80f4bSopenharmony_ci auto ecsObject = CreateNewEcsObject({}); 10658bf80f4bSopenharmony_ci auto nodeInterface = interface_pointer_cast<INodeEcsInterfacePrivate>(node); 10668bf80f4bSopenharmony_ci nodeInterface->Initialize(ecsScene, ecsObject, {}, "", name, sceneHolder_, entity); 10678bf80f4bSopenharmony_ci } 10688bf80f4bSopenharmony_ci } 10698bf80f4bSopenharmony_ci } 10708bf80f4bSopenharmony_ci 10718bf80f4bSopenharmony_ci return node; 10728bf80f4bSopenharmony_ci } 10738bf80f4bSopenharmony_ci 10748bf80f4bSopenharmony_ci void BindNodeToEcs( 10758bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr& node, const BASE_NS::string_view fullPath, bool createEngineObject) override 10768bf80f4bSopenharmony_ci { 10778bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("Scene::BindNodeToEcs called for %s", BASE_NS::string(fullPath).c_str()); 10788bf80f4bSopenharmony_ci 10798bf80f4bSopenharmony_ci CORE_NS::Entity entity; 10808bf80f4bSopenharmony_ci auto ecsScene = GetSelf<SCENE_NS::IEcsScene>(); 10818bf80f4bSopenharmony_ci 10828bf80f4bSopenharmony_ci bool addToRootContainer { false }; 10838bf80f4bSopenharmony_ci BASE_NS::string nodePath; 10848bf80f4bSopenharmony_ci BASE_NS::string nodeName; 10858bf80f4bSopenharmony_ci 10868bf80f4bSopenharmony_ci auto classUid = interface_cast<META_NS::IObject>(node)->GetClassId(); 10878bf80f4bSopenharmony_ci bool isResourceClassType = (classUid == SCENE_NS::ClassId::Material) || // Material 10888bf80f4bSopenharmony_ci (classUid == SCENE_NS::ClassId::Mesh) || // Mesh 10898bf80f4bSopenharmony_ci (classUid == SCENE_NS::ClassId::Animation); // Animation 10908bf80f4bSopenharmony_ci 10918bf80f4bSopenharmony_ci auto isRealUri = fullPath.find("://") != BASE_NS::string_view::npos; 10928bf80f4bSopenharmony_ci 10938bf80f4bSopenharmony_ci if (!isRealUri) { 10948bf80f4bSopenharmony_ci auto cutIx = fullPath.find_last_of('/'); 10958bf80f4bSopenharmony_ci if (cutIx != BASE_NS::string_view::npos && cutIx < fullPath.size()) { 10968bf80f4bSopenharmony_ci ++cutIx; 10978bf80f4bSopenharmony_ci nodePath = BASE_NS::string(fullPath.data(), cutIx); 10988bf80f4bSopenharmony_ci nodeName = BASE_NS::string(fullPath.data() + cutIx, fullPath.size() - cutIx); 10998bf80f4bSopenharmony_ci } else if (!fullPath.empty()) { 11008bf80f4bSopenharmony_ci nodeName = BASE_NS::string(fullPath.data(), fullPath.size()); 11018bf80f4bSopenharmony_ci } 11028bf80f4bSopenharmony_ci } 11038bf80f4bSopenharmony_ci 11048bf80f4bSopenharmony_ci if (nodeName.empty()) { 11058bf80f4bSopenharmony_ci if (createEngineObject) { 11068bf80f4bSopenharmony_ci nodeName = interface_cast<META_NS::IObjectInstance>(node)->GetInstanceId().ToString(); 11078bf80f4bSopenharmony_ci } else { 11088bf80f4bSopenharmony_ci if (isRealUri) { 11098bf80f4bSopenharmony_ci auto ecsObject = CreateNewEcsObject({}); 11108bf80f4bSopenharmony_ci auto nodeInterface = interface_cast<INodeEcsInterfacePrivate>(node); 11118bf80f4bSopenharmony_ci nodeInterface->Initialize(ecsScene, ecsObject, {}, "", BASE_NS::string(fullPath), sceneHolder_, {}); 11128bf80f4bSopenharmony_ci } else { 11138bf80f4bSopenharmony_ci CORE_LOG_W("%s: refusing to create proxy object without valid target, name is empty.", __func__); 11148bf80f4bSopenharmony_ci } 11158bf80f4bSopenharmony_ci return; 11168bf80f4bSopenharmony_ci } 11178bf80f4bSopenharmony_ci } 11188bf80f4bSopenharmony_ci 11198bf80f4bSopenharmony_ci auto nodeInterface = interface_cast<INodeEcsInterfacePrivate>(node); 11208bf80f4bSopenharmony_ci 11218bf80f4bSopenharmony_ci if (nodeInterface->EcsObject() && CORE_NS::EntityUtil::IsValid(nodeInterface->EcsObject()->GetEntity())) { 11228bf80f4bSopenharmony_ci CORE_LOG_W("%s: refusing to recreate proxy object while current one is valid: %s", __func__, 11238bf80f4bSopenharmony_ci BASE_NS::string(fullPath).c_str()); 11248bf80f4bSopenharmony_ci return; 11258bf80f4bSopenharmony_ci } 11268bf80f4bSopenharmony_ci 11278bf80f4bSopenharmony_ci auto ecsObject = CreateNewEcsObject({}); 11288bf80f4bSopenharmony_ci 11298bf80f4bSopenharmony_ci // NEW NODE 11308bf80f4bSopenharmony_ci if (createEngineObject) { 11318bf80f4bSopenharmony_ci auto classUid = interface_pointer_cast<META_NS::IObject>(node)->GetClassId(); 11328bf80f4bSopenharmony_ci auto constructNode = [this, nodePath, nodeName, classUid]( 11338bf80f4bSopenharmony_ci const auto& sceneHolder) -> CORE_NS::Entity { 11348bf80f4bSopenharmony_ci CORE_NS::Entity entity; 11358bf80f4bSopenharmony_ci if (sceneHolder) { 11368bf80f4bSopenharmony_ci // Should not need to type this deep here 11378bf80f4bSopenharmony_ci if (classUid == SCENE_NS::ClassId::Material) { 11388bf80f4bSopenharmony_ci entity = sceneHolder->CreateMaterial(nodeName); 11398bf80f4bSopenharmony_ci } else if (classUid == SCENE_NS::ClassId::Camera) { 11408bf80f4bSopenharmony_ci entity = sceneHolder->CreateCamera(nodePath, nodeName, 0); 11418bf80f4bSopenharmony_ci } else if (auto node = sceneHolder->CreateNode(nodePath, nodeName)) { 11428bf80f4bSopenharmony_ci entity = node->GetEntity(); 11438bf80f4bSopenharmony_ci 11448bf80f4bSopenharmony_ci sceneHolder->EnableLayerComponent(entity); 11458bf80f4bSopenharmony_ci if (classUid == SCENE_NS::ClassId::Light) { 11468bf80f4bSopenharmony_ci sceneHolder->EnableLightComponent(entity); 11478bf80f4bSopenharmony_ci } 11488bf80f4bSopenharmony_ci if (classUid == SCENE_NS::ClassId::Environment) { 11498bf80f4bSopenharmony_ci sceneHolder->EnableEnvironmentComponent(entity); 11508bf80f4bSopenharmony_ci } 11518bf80f4bSopenharmony_ci } 11528bf80f4bSopenharmony_ci } 11538bf80f4bSopenharmony_ci 11548bf80f4bSopenharmony_ci return entity; 11558bf80f4bSopenharmony_ci }; 11568bf80f4bSopenharmony_ci if (GetValue(Asynchronous())) { 11578bf80f4bSopenharmony_ci AddEngineTask(MakeTask( 11588bf80f4bSopenharmony_ci [constructNode](const auto& sceneHolder) { 11598bf80f4bSopenharmony_ci constructNode(sceneHolder); 11608bf80f4bSopenharmony_ci return false; 11618bf80f4bSopenharmony_ci }, 11628bf80f4bSopenharmony_ci sceneHolder_), 11638bf80f4bSopenharmony_ci false); 11648bf80f4bSopenharmony_ci } else { 11658bf80f4bSopenharmony_ci entity = constructNode(sceneHolder_); 11668bf80f4bSopenharmony_ci } 11678bf80f4bSopenharmony_ci 11688bf80f4bSopenharmony_ci addToRootContainer = true; 11698bf80f4bSopenharmony_ci // If we don't have parent .. then attach to root. 11708bf80f4bSopenharmony_ci if (nodePath.empty() && !isResourceClassType) { 11718bf80f4bSopenharmony_ci nodePath = "/" + rootNodeId_ + "/"; 11728bf80f4bSopenharmony_ci } 11738bf80f4bSopenharmony_ci 11748bf80f4bSopenharmony_ci if (META_NS::Property<uint32_t> creationPolicy = nodeInterface->GetLifecycleInfo()) { 11758bf80f4bSopenharmony_ci creationPolicy->SetValue(NODE_LC_CREATED); 11768bf80f4bSopenharmony_ci nodeInterface->ClaimOwnershipOfEntity(true); 11778bf80f4bSopenharmony_ci } 11788bf80f4bSopenharmony_ci } else { 11798bf80f4bSopenharmony_ci // We expect to find the node from ecs (sooner or later) 11808bf80f4bSopenharmony_ci // If we are running synchronously, we could check it and even 11818bf80f4bSopenharmony_ci // tell the calling code if the node is there. 11828bf80f4bSopenharmony_ci 11838bf80f4bSopenharmony_ci // We'd need to know some additional info about the node parent etc 11848bf80f4bSopenharmony_ci if (META_NS::Property<uint32_t> creationPolicy = nodeInterface->GetLifecycleInfo()) { 11858bf80f4bSopenharmony_ci creationPolicy->SetValue(NODE_LC_MIRROR_EXISTING); 11868bf80f4bSopenharmony_ci } 11878bf80f4bSopenharmony_ci } 11888bf80f4bSopenharmony_ci 11898bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr parent; 11908bf80f4bSopenharmony_ci 11918bf80f4bSopenharmony_ci if (!isResourceClassType) { 11928bf80f4bSopenharmony_ci auto containable = interface_cast<META_NS::IContainable>(node); 11938bf80f4bSopenharmony_ci if (containable->GetParent()) { 11948bf80f4bSopenharmony_ci parent = interface_pointer_cast<SCENE_NS::INode>(containable->GetParent()); 11958bf80f4bSopenharmony_ci } 11968bf80f4bSopenharmony_ci 11978bf80f4bSopenharmony_ci if (!parent) { 11988bf80f4bSopenharmony_ci parent = addToRootContainer ? RootNode()->GetValue() : currentParent_; 11998bf80f4bSopenharmony_ci } 12008bf80f4bSopenharmony_ci } 12018bf80f4bSopenharmony_ci 12028bf80f4bSopenharmony_ci nodeInterface->Initialize(ecsScene, ecsObject, parent, nodePath, nodeName, sceneHolder_, entity); 12038bf80f4bSopenharmony_ci } 12048bf80f4bSopenharmony_ci 12058bf80f4bSopenharmony_ci void UpdateCachedNodePath(const SCENE_NS::INode::Ptr& node) override 12068bf80f4bSopenharmony_ci { 12078bf80f4bSopenharmony_ci if (node) { 12088bf80f4bSopenharmony_ci if (interface_cast<META_NS::IObject>(node)->GetClassId() != SCENE_NS::ClassId::Node) { 12098bf80f4bSopenharmony_ci UpdateCachedReference(node); 12108bf80f4bSopenharmony_ci return; 12118bf80f4bSopenharmony_ci } 12128bf80f4bSopenharmony_ci 12138bf80f4bSopenharmony_ci bool found = false; 12148bf80f4bSopenharmony_ci 12158bf80f4bSopenharmony_ci for (auto&& ite : nodes_) { 12168bf80f4bSopenharmony_ci if (ite.second == node) { 12178bf80f4bSopenharmony_ci nodes_.erase(ite.first); 12188bf80f4bSopenharmony_ci break; 12198bf80f4bSopenharmony_ci } 12208bf80f4bSopenharmony_ci } 12218bf80f4bSopenharmony_ci 12228bf80f4bSopenharmony_ci BASE_NS::string pathString = node->Path()->GetValue(); 12238bf80f4bSopenharmony_ci pathString.append(node->Name()->GetValue()); 12248bf80f4bSopenharmony_ci nodes_[pathString] = node; 12258bf80f4bSopenharmony_ci } 12268bf80f4bSopenharmony_ci } 12278bf80f4bSopenharmony_ci 12288bf80f4bSopenharmony_ci void SetCacheEnabled(const SCENE_NS::INode::Ptr& node, bool enabled) override 12298bf80f4bSopenharmony_ci { 12308bf80f4bSopenharmony_ci if (!node) { 12318bf80f4bSopenharmony_ci return; 12328bf80f4bSopenharmony_ci } 12338bf80f4bSopenharmony_ci 12348bf80f4bSopenharmony_ci if (enabled) { 12358bf80f4bSopenharmony_ci BASE_NS::string pathString = node->Path()->GetValue(); 12368bf80f4bSopenharmony_ci pathString.append(node->Name()->GetValue()); 12378bf80f4bSopenharmony_ci nodes_[pathString] = node; 12388bf80f4bSopenharmony_ci } else { 12398bf80f4bSopenharmony_ci for (auto&& ite : nodes_) { 12408bf80f4bSopenharmony_ci if (ite.second == node) { 12418bf80f4bSopenharmony_ci nodes_.erase(ite.first); 12428bf80f4bSopenharmony_ci break; 12438bf80f4bSopenharmony_ci } 12448bf80f4bSopenharmony_ci } 12458bf80f4bSopenharmony_ci } 12468bf80f4bSopenharmony_ci } 12478bf80f4bSopenharmony_ci 12488bf80f4bSopenharmony_ci typedef BASE_NS::shared_ptr<CORE_NS::IInterface> (*fun)(SceneImpl* me, const BASE_NS::string_view); 12498bf80f4bSopenharmony_ci 12508bf80f4bSopenharmony_ci static BASE_NS::shared_ptr<CORE_NS::IInterface> relmat(SceneImpl* me, const BASE_NS::string_view p) 12518bf80f4bSopenharmony_ci { 12528bf80f4bSopenharmony_ci return me->ReleaseMaterial(p); 12538bf80f4bSopenharmony_ci } 12548bf80f4bSopenharmony_ci static BASE_NS::shared_ptr<CORE_NS::IInterface> relmesh(SceneImpl* me, const BASE_NS::string_view p) 12558bf80f4bSopenharmony_ci { 12568bf80f4bSopenharmony_ci return me->ReleaseMesh(p); 12578bf80f4bSopenharmony_ci } 12588bf80f4bSopenharmony_ci static BASE_NS::shared_ptr<CORE_NS::IInterface> relanim(SceneImpl* me, const BASE_NS::string_view p) 12598bf80f4bSopenharmony_ci { 12608bf80f4bSopenharmony_ci return me->ReleaseAnimation(p); 12618bf80f4bSopenharmony_ci } 12628bf80f4bSopenharmony_ci static BASE_NS::shared_ptr<CORE_NS::IInterface> relnode(SceneImpl* me, const BASE_NS::string_view p) 12638bf80f4bSopenharmony_ci { 12648bf80f4bSopenharmony_ci return me->ReleaseNode(p); 12658bf80f4bSopenharmony_ci } 12668bf80f4bSopenharmony_ci template<typename Type> 12678bf80f4bSopenharmony_ci bool CacheNode(const char* const tname, const SCENE_NS::INode::Ptr& node, 12688bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, typename Type::WeakPtr>& cache, fun func) 12698bf80f4bSopenharmony_ci { 12708bf80f4bSopenharmony_ci if (auto typed = interface_pointer_cast<Type>(node)) { 12718bf80f4bSopenharmony_ci BASE_NS::string uri; 12728bf80f4bSopenharmony_ci bool found = false; 12738bf80f4bSopenharmony_ci 12748bf80f4bSopenharmony_ci if (node->GetInterface(SCENE_NS::ICamera::UID)) { 12758bf80f4bSopenharmony_ci // handle camera naming.. 12768bf80f4bSopenharmony_ci uri = node->Path()->GetValue(); 12778bf80f4bSopenharmony_ci uri.append(node->Name()->GetValue()); 12788bf80f4bSopenharmony_ci 12798bf80f4bSopenharmony_ci } else { 12808bf80f4bSopenharmony_ci auto ecsObject = interface_pointer_cast<SCENE_NS::IEcsObject>(typed); 12818bf80f4bSopenharmony_ci uri = sceneHolder_->GetResourceId(ecsObject->GetEntity()); 12828bf80f4bSopenharmony_ci if (uri.empty()) { 12838bf80f4bSopenharmony_ci uri = node->Name()->GetValue() + ":" + BASE_NS::to_hex(ecsObject->GetEntity().id); 12848bf80f4bSopenharmony_ci } 12858bf80f4bSopenharmony_ci } 12868bf80f4bSopenharmony_ci 12878bf80f4bSopenharmony_ci for (auto&& ite : cache) { 12888bf80f4bSopenharmony_ci if (ite.second.lock() == typed) { 12898bf80f4bSopenharmony_ci if (uri != ite.first) { 12908bf80f4bSopenharmony_ci cache[uri] = interface_pointer_cast<Type>(func(this, ite.first)); 12918bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("Updating cached reference of %s: %s", tname, uri.c_str()); 12928bf80f4bSopenharmony_ci } 12938bf80f4bSopenharmony_ci found = true; 12948bf80f4bSopenharmony_ci break; // reference is valid so return true regardless if the node was moved 12958bf80f4bSopenharmony_ci } 12968bf80f4bSopenharmony_ci } 12978bf80f4bSopenharmony_ci 12988bf80f4bSopenharmony_ci if (!found) { 12998bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("Caching reference of %s: %s", tname, uri.c_str()); 13008bf80f4bSopenharmony_ci cache[uri] = typed; 13018bf80f4bSopenharmony_ci } 13028bf80f4bSopenharmony_ci return true; 13038bf80f4bSopenharmony_ci } 13048bf80f4bSopenharmony_ci return false; 13058bf80f4bSopenharmony_ci } 13068bf80f4bSopenharmony_ci void UpdateCachedReference(const SCENE_NS::INode::Ptr& node) override 13078bf80f4bSopenharmony_ci { 13088bf80f4bSopenharmony_ci if (node) { 13098bf80f4bSopenharmony_ci if (CacheNode<SCENE_NS::IMaterial>("material", node, materials_, relmat) || 13108bf80f4bSopenharmony_ci CacheNode<SCENE_NS::IMesh>("mesh", node, meshes_, relmesh) || 13118bf80f4bSopenharmony_ci CacheNode<META_NS::IAnimation>("animation", node, animations_, relanim)) { 13128bf80f4bSopenharmony_ci // completed. (meshes, materials and animations are not added to node list) 13138bf80f4bSopenharmony_ci return; 13148bf80f4bSopenharmony_ci } 13158bf80f4bSopenharmony_ci if (CacheNode<SCENE_NS::ICamera>("camera", node, cameras_, relnode)) { 13168bf80f4bSopenharmony_ci // camera cache updated. 13178bf80f4bSopenharmony_ci auto* obj = interface_cast<SCENE_NS::IEcsObject>(node); 13188bf80f4bSopenharmony_ci if (obj) { 13198bf80f4bSopenharmony_ci auto entity = obj->GetEntity(); 13208bf80f4bSopenharmony_ci if (CORE_NS::EntityUtil::IsValid(entity)) { 13218bf80f4bSopenharmony_ci sceneHolder_->AddCamera(entity); 13228bf80f4bSopenharmony_ci } else { 13238bf80f4bSopenharmony_ci CORE_LOG_V("camera has no entity id yet"); 13248bf80f4bSopenharmony_ci } 13258bf80f4bSopenharmony_ci } else { 13268bf80f4bSopenharmony_ci CORE_LOG_V("camera has no IEcsObject"); 13278bf80f4bSopenharmony_ci } 13288bf80f4bSopenharmony_ci } 13298bf80f4bSopenharmony_ci // update node cache. 13308bf80f4bSopenharmony_ci 13318bf80f4bSopenharmony_ci bool found = false; 13328bf80f4bSopenharmony_ci BASE_NS::string uri = node->Path()->GetValue(); 13338bf80f4bSopenharmony_ci uri.append(node->Name()->GetValue()); 13348bf80f4bSopenharmony_ci 13358bf80f4bSopenharmony_ci for (auto&& ite : nodes_) { 13368bf80f4bSopenharmony_ci if (ite.second == node) { 13378bf80f4bSopenharmony_ci if (uri != ite.first) { 13388bf80f4bSopenharmony_ci nodes_[uri] = ReleaseNode(ite.first); 13398bf80f4bSopenharmony_ci } 13408bf80f4bSopenharmony_ci found = true; 13418bf80f4bSopenharmony_ci break; // reference is valid so return true regardless if the node was moved 13428bf80f4bSopenharmony_ci } 13438bf80f4bSopenharmony_ci } 13448bf80f4bSopenharmony_ci 13458bf80f4bSopenharmony_ci if (!found) { 13468bf80f4bSopenharmony_ci nodes_[uri] = node; 13478bf80f4bSopenharmony_ci } 13488bf80f4bSopenharmony_ci } 13498bf80f4bSopenharmony_ci } 13508bf80f4bSopenharmony_ci 13518bf80f4bSopenharmony_ci // Release Node Reference from cache 13528bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr ReleaseNode(const BASE_NS::string_view name) override 13538bf80f4bSopenharmony_ci { 13548bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr ret {}; 13558bf80f4bSopenharmony_ci if (auto ite = nodes_.extract(BASE_NS::string(name)); !ite.empty()) { 13568bf80f4bSopenharmony_ci ret = BASE_NS::move(ite.mapped()); 13578bf80f4bSopenharmony_ci if (auto privateIntf = interface_cast<INodeEcsInterfacePrivate>(ret)) { 13588bf80f4bSopenharmony_ci privateIntf->ClaimOwnershipOfEntity(true); 13598bf80f4bSopenharmony_ci } 13608bf80f4bSopenharmony_ci RemoveNodeFromCurrentContainer(ret); 13618bf80f4bSopenharmony_ci if (auto cam = interface_pointer_cast<SCENE_NS::ICamera>(ret)) { 13628bf80f4bSopenharmony_ci ReleaseCamera(name); 13638bf80f4bSopenharmony_ci } 13648bf80f4bSopenharmony_ci } 13658bf80f4bSopenharmony_ci return ret; 13668bf80f4bSopenharmony_ci } 13678bf80f4bSopenharmony_ci void ReleaseNode(const SCENE_NS::INode::Ptr& node) override 13688bf80f4bSopenharmony_ci { 13698bf80f4bSopenharmony_ci if (node) { 13708bf80f4bSopenharmony_ci ReleaseNode(node->Path()->GetValue() + node->Name()->GetValue()); 13718bf80f4bSopenharmony_ci } 13728bf80f4bSopenharmony_ci } 13738bf80f4bSopenharmony_ci 13748bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr ReleaseMaterial(const BASE_NS::string_view name) override 13758bf80f4bSopenharmony_ci { 13768bf80f4bSopenharmony_ci SCENE_NS::IMaterial::Ptr ret {}; 13778bf80f4bSopenharmony_ci if (auto ite = materials_.find(name); ite != materials_.end()) { 13788bf80f4bSopenharmony_ci ret = ite->second.lock(); 13798bf80f4bSopenharmony_ci materials_.erase(ite); 13808bf80f4bSopenharmony_ci } 13818bf80f4bSopenharmony_ci return ret; 13828bf80f4bSopenharmony_ci } 13838bf80f4bSopenharmony_ci 13848bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr ReleaseMesh(const BASE_NS::string_view name) override 13858bf80f4bSopenharmony_ci { 13868bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr ret {}; 13878bf80f4bSopenharmony_ci if (auto ite = meshes_.find(name); ite != meshes_.end()) { 13888bf80f4bSopenharmony_ci ret = ite->second.lock(); 13898bf80f4bSopenharmony_ci meshes_.erase(ite); 13908bf80f4bSopenharmony_ci } 13918bf80f4bSopenharmony_ci 13928bf80f4bSopenharmony_ci return ret; 13938bf80f4bSopenharmony_ci } 13948bf80f4bSopenharmony_ci 13958bf80f4bSopenharmony_ci META_NS::IAnimation::Ptr ReleaseAnimation(const BASE_NS::string_view name) override 13968bf80f4bSopenharmony_ci { 13978bf80f4bSopenharmony_ci META_NS::IAnimation::Ptr ret {}; 13988bf80f4bSopenharmony_ci if (auto ite = animations_.find(name); ite != animations_.end()) { 13998bf80f4bSopenharmony_ci ret = ite->second.lock(); 14008bf80f4bSopenharmony_ci animations_.erase(ite); 14018bf80f4bSopenharmony_ci } 14028bf80f4bSopenharmony_ci return ret; 14038bf80f4bSopenharmony_ci } 14048bf80f4bSopenharmony_ci 14058bf80f4bSopenharmony_ci SCENE_NS::ICamera::Ptr ReleaseCamera(const BASE_NS::string_view name) 14068bf80f4bSopenharmony_ci { 14078bf80f4bSopenharmony_ci SCENE_NS::ICamera::Ptr ret {}; 14088bf80f4bSopenharmony_ci if (auto ite = cameras_.find(name); ite != cameras_.end()) { 14098bf80f4bSopenharmony_ci ret = ite->second.lock(); 14108bf80f4bSopenharmony_ci // make sure the rendertarget/bitmap is also released. 14118bf80f4bSopenharmony_ci SetBitmap(nullptr, ret); 14128bf80f4bSopenharmony_ci cameras_.erase(ite); 14138bf80f4bSopenharmony_ci } 14148bf80f4bSopenharmony_ci return ret; 14158bf80f4bSopenharmony_ci } 14168bf80f4bSopenharmony_ci 14178bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr CreateMeshFromArraysI16( 14188bf80f4bSopenharmony_ci const BASE_NS::string_view name, SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays) override 14198bf80f4bSopenharmony_ci { 14208bf80f4bSopenharmony_ci return CreateMeshFromArrays<uint16_t>(name, arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT16); 14218bf80f4bSopenharmony_ci } 14228bf80f4bSopenharmony_ci 14238bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr CreateMeshFromArraysI32( 14248bf80f4bSopenharmony_ci const BASE_NS::string_view name, SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays) override 14258bf80f4bSopenharmony_ci { 14268bf80f4bSopenharmony_ci return CreateMeshFromArrays<uint32_t>(name, arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT32); 14278bf80f4bSopenharmony_ci } 14288bf80f4bSopenharmony_ci 14298bf80f4bSopenharmony_ci template<typename IndicesType> 14308bf80f4bSopenharmony_ci SCENE_NS::IMesh::Ptr CreateMeshFromArrays(const BASE_NS::string_view name, 14318bf80f4bSopenharmony_ci SCENE_NS::MeshGeometryArrayPtr<IndicesType> arrays, RENDER_NS::IndexType indexType) 14328bf80f4bSopenharmony_ci { 14338bf80f4bSopenharmony_ci auto nameString = BASE_NS::shared_ptr(new BASE_NS::string(name.data(), name.size())); 14348bf80f4bSopenharmony_ci 14358bf80f4bSopenharmony_ci AddEngineTask(MakeTask( 14368bf80f4bSopenharmony_ci [arrays, nameString, indexType](auto sceneHolder) { 14378bf80f4bSopenharmony_ci auto meshEntity = sceneHolder->template CreateMeshFromArrays<IndicesType>( 14388bf80f4bSopenharmony_ci *nameString, arrays, indexType); 14398bf80f4bSopenharmony_ci if (!sceneHolder->IsAsync()) { 14408bf80f4bSopenharmony_ci *nameString = sceneHolder->GetResourceId(meshEntity); 14418bf80f4bSopenharmony_ci } 14428bf80f4bSopenharmony_ci 14438bf80f4bSopenharmony_ci return false; 14448bf80f4bSopenharmony_ci }, 14458bf80f4bSopenharmony_ci sceneHolder_), 14468bf80f4bSopenharmony_ci false); 14478bf80f4bSopenharmony_ci return GetMesh(*nameString); 14488bf80f4bSopenharmony_ci } 14498bf80f4bSopenharmony_ci 14508bf80f4bSopenharmony_ci void InstantiateMaterialProxies() override 14518bf80f4bSopenharmony_ci { 14528bf80f4bSopenharmony_ci AddEngineTask(MakeTask( 14538bf80f4bSopenharmony_ci [me = BASE_NS::weak_ptr(GetSelf<SCENE_NS::IScene>())](auto sceneHolder) { 14548bf80f4bSopenharmony_ci auto ids = sceneHolder->ListMaterialNames(); 14558bf80f4bSopenharmony_ci sceneHolder->QueueApplicationTask(MakeTask( 14568bf80f4bSopenharmony_ci [ids](auto self) { 14578bf80f4bSopenharmony_ci for (auto& id : *ids) { 14588bf80f4bSopenharmony_ci self->GetMaterial(id); 14598bf80f4bSopenharmony_ci } 14608bf80f4bSopenharmony_ci return false; 14618bf80f4bSopenharmony_ci }, 14628bf80f4bSopenharmony_ci me), 14638bf80f4bSopenharmony_ci false); 14648bf80f4bSopenharmony_ci return false; 14658bf80f4bSopenharmony_ci }, 14668bf80f4bSopenharmony_ci sceneHolder_), 14678bf80f4bSopenharmony_ci false); 14688bf80f4bSopenharmony_ci } 14698bf80f4bSopenharmony_ci 14708bf80f4bSopenharmony_ci void InstantiateMeshProxies() override 14718bf80f4bSopenharmony_ci { 14728bf80f4bSopenharmony_ci AddEngineTask(MakeTask( 14738bf80f4bSopenharmony_ci [me = BASE_NS::weak_ptr(GetSelf<SCENE_NS::IScene>())](auto sceneHolder) { 14748bf80f4bSopenharmony_ci auto ids = sceneHolder->ListMeshNames(); 14758bf80f4bSopenharmony_ci sceneHolder->QueueApplicationTask(MakeTask( 14768bf80f4bSopenharmony_ci [ids](auto self) { 14778bf80f4bSopenharmony_ci for (auto& id : *ids) { 14788bf80f4bSopenharmony_ci self->GetMesh(id); 14798bf80f4bSopenharmony_ci } 14808bf80f4bSopenharmony_ci 14818bf80f4bSopenharmony_ci return false; 14828bf80f4bSopenharmony_ci }, 14838bf80f4bSopenharmony_ci me), 14848bf80f4bSopenharmony_ci false); 14858bf80f4bSopenharmony_ci 14868bf80f4bSopenharmony_ci return false; 14878bf80f4bSopenharmony_ci }, 14888bf80f4bSopenharmony_ci sceneHolder_), 14898bf80f4bSopenharmony_ci false); 14908bf80f4bSopenharmony_ci } 14918bf80f4bSopenharmony_ci 14928bf80f4bSopenharmony_cipublic: 14938bf80f4bSopenharmony_ci ~SceneImpl() override 14948bf80f4bSopenharmony_ci { 14958bf80f4bSopenharmony_ci allAnims_.clear(); 14968bf80f4bSopenharmony_ci if (sceneHolder_) { 14978bf80f4bSopenharmony_ci DetachScene(); 14988bf80f4bSopenharmony_ci } 14998bf80f4bSopenharmony_ci 15008bf80f4bSopenharmony_ci cameraNodePtr_.reset(); 15018bf80f4bSopenharmony_ci rootNodePtr_.reset(); 15028bf80f4bSopenharmony_ci 15038bf80f4bSopenharmony_ci UnsubscribeFromPropertyChanges(); 15048bf80f4bSopenharmony_ci 15058bf80f4bSopenharmony_ci if (sceneHolder_) { 15068bf80f4bSopenharmony_ci sceneHolder_->Uninitialize(); 15078bf80f4bSopenharmony_ci sceneHolder_.reset(); 15088bf80f4bSopenharmony_ci } 15098bf80f4bSopenharmony_ci } 15108bf80f4bSopenharmony_ci 15118bf80f4bSopenharmony_ci void SetEcsInitializationCallback(IPrepareSceneForInitialization::WeakPtr callback) override 15128bf80f4bSopenharmony_ci { 15138bf80f4bSopenharmony_ci if (sceneHolder_) { 15148bf80f4bSopenharmony_ci sceneHolder_->SetEcsInitializationCallback(callback); 15158bf80f4bSopenharmony_ci } else { 15168bf80f4bSopenharmony_ci CORE_LOG_W("%s: sceneholder does not exist, cannot set callback", __func__); 15178bf80f4bSopenharmony_ci } 15188bf80f4bSopenharmony_ci } 15198bf80f4bSopenharmony_ci 15208bf80f4bSopenharmony_ci SCENE_NS::IPickingResult::Ptr GetWorldAABB(const BASE_NS::Math::Mat4X4& world, const BASE_NS::Math::Vec3& aabbMin, 15218bf80f4bSopenharmony_ci const BASE_NS::Math::Vec3& aabbMax) override 15228bf80f4bSopenharmony_ci { 15238bf80f4bSopenharmony_ci auto ret = META_NS::GetObjectRegistry().Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request); 15248bf80f4bSopenharmony_ci if (ret) { 15258bf80f4bSopenharmony_ci AddEngineTask( 15268bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::ITaskQueueTask>([w = world, min = aabbMin, max = aabbMax, 15278bf80f4bSopenharmony_ci weakRet = BASE_NS::weak_ptr(ret), 15288bf80f4bSopenharmony_ci weakSh = BASE_NS::weak_ptr(sceneHolder_)]() { 15298bf80f4bSopenharmony_ci if (auto sh = weakSh.lock()) { 15308bf80f4bSopenharmony_ci if (auto ret = weakRet.lock()) { 15318bf80f4bSopenharmony_ci if (sh->GetWorldAABB(ret, w, min, max)) { 15328bf80f4bSopenharmony_ci sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() { 15338bf80f4bSopenharmony_ci if (auto writable = 15348bf80f4bSopenharmony_ci interface_pointer_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>( 15358bf80f4bSopenharmony_ci weakRet)) { 15368bf80f4bSopenharmony_ci writable->MarkReady(); 15378bf80f4bSopenharmony_ci } 15388bf80f4bSopenharmony_ci return false; 15398bf80f4bSopenharmony_ci }), 15408bf80f4bSopenharmony_ci false); 15418bf80f4bSopenharmony_ci } 15428bf80f4bSopenharmony_ci } 15438bf80f4bSopenharmony_ci } 15448bf80f4bSopenharmony_ci return false; 15458bf80f4bSopenharmony_ci }), 15468bf80f4bSopenharmony_ci false); 15478bf80f4bSopenharmony_ci return ret; 15488bf80f4bSopenharmony_ci } 15498bf80f4bSopenharmony_ci return SCENE_NS::IPickingResult::Ptr(); 15508bf80f4bSopenharmony_ci } 15518bf80f4bSopenharmony_ci 15528bf80f4bSopenharmony_ci SCENE_NS::IRayCastResult::Ptr RayCast( 15538bf80f4bSopenharmony_ci const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction) override 15548bf80f4bSopenharmony_ci { 15558bf80f4bSopenharmony_ci auto ret = 15568bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest); 15578bf80f4bSopenharmony_ci if (ret) { 15588bf80f4bSopenharmony_ci AddEngineTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([origin = start, dir = direction, 15598bf80f4bSopenharmony_ci weakRet = BASE_NS::weak_ptr(ret), 15608bf80f4bSopenharmony_ci weakSh = BASE_NS::weak_ptr(sceneHolder_), 15618bf80f4bSopenharmony_ci weakSelf = BASE_NS::weak_ptr( 15628bf80f4bSopenharmony_ci GetSelf<SCENE_NS::IScene>())]() { 15638bf80f4bSopenharmony_ci if (auto sh = weakSh.lock()) { 15648bf80f4bSopenharmony_ci if (auto ret = weakRet.lock()) { 15658bf80f4bSopenharmony_ci if (sh->RayCast(ret, origin, dir)) { 15668bf80f4bSopenharmony_ci sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, 15678bf80f4bSopenharmony_ci weakSelf]() { 15688bf80f4bSopenharmony_ci if (auto writable = 15698bf80f4bSopenharmony_ci interface_pointer_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>( 15708bf80f4bSopenharmony_ci weakRet)) { 15718bf80f4bSopenharmony_ci if (auto self = weakSelf.lock()) { 15728bf80f4bSopenharmony_ci // resolve proxy nodes 15738bf80f4bSopenharmony_ci for (size_t ii = writable->MetaData().size(); ii > 0;) { 15748bf80f4bSopenharmony_ci --ii; 15758bf80f4bSopenharmony_ci writable->MutableData().at(ii).node = 15768bf80f4bSopenharmony_ci self->GetNode(writable->MetaData().at(ii)); 15778bf80f4bSopenharmony_ci } 15788bf80f4bSopenharmony_ci writable->MarkReady(); 15798bf80f4bSopenharmony_ci } 15808bf80f4bSopenharmony_ci } 15818bf80f4bSopenharmony_ci return false; 15828bf80f4bSopenharmony_ci }), 15838bf80f4bSopenharmony_ci false); 15848bf80f4bSopenharmony_ci } 15858bf80f4bSopenharmony_ci } 15868bf80f4bSopenharmony_ci } 15878bf80f4bSopenharmony_ci return false; 15888bf80f4bSopenharmony_ci }), 15898bf80f4bSopenharmony_ci false); 15908bf80f4bSopenharmony_ci return ret; 15918bf80f4bSopenharmony_ci } 15928bf80f4bSopenharmony_ci return SCENE_NS::IRayCastResult::Ptr(); 15938bf80f4bSopenharmony_ci } 15948bf80f4bSopenharmony_ci 15958bf80f4bSopenharmony_ci SCENE_NS::IRayCastResult::Ptr RayCast( 15968bf80f4bSopenharmony_ci const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction, uint64_t layerMask) override 15978bf80f4bSopenharmony_ci { 15988bf80f4bSopenharmony_ci auto ret = 15998bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest); 16008bf80f4bSopenharmony_ci if (ret) { 16018bf80f4bSopenharmony_ci AddEngineTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([origin = start, dir = direction, layerMask, 16028bf80f4bSopenharmony_ci weakRet = BASE_NS::weak_ptr(ret), 16038bf80f4bSopenharmony_ci weakSh = BASE_NS::weak_ptr(sceneHolder_), 16048bf80f4bSopenharmony_ci weakSelf = BASE_NS::weak_ptr( 16058bf80f4bSopenharmony_ci GetSelf<SCENE_NS::IScene>())]() { 16068bf80f4bSopenharmony_ci if (auto sh = weakSh.lock()) { 16078bf80f4bSopenharmony_ci if (auto ret = weakRet.lock()) { 16088bf80f4bSopenharmony_ci if (sh->RayCast(ret, origin, dir, layerMask)) { 16098bf80f4bSopenharmony_ci sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, 16108bf80f4bSopenharmony_ci weakSelf]() { 16118bf80f4bSopenharmony_ci if (auto writable = 16128bf80f4bSopenharmony_ci interface_pointer_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>( 16138bf80f4bSopenharmony_ci weakRet)) { 16148bf80f4bSopenharmony_ci if (auto self = weakSelf.lock()) { 16158bf80f4bSopenharmony_ci // resolve proxy nodes 16168bf80f4bSopenharmony_ci for (size_t ii = writable->MetaData().size(); ii > 0;) { 16178bf80f4bSopenharmony_ci --ii; 16188bf80f4bSopenharmony_ci writable->MutableData().at(ii).node = 16198bf80f4bSopenharmony_ci self->GetNode(writable->MetaData().at(ii)); 16208bf80f4bSopenharmony_ci } 16218bf80f4bSopenharmony_ci writable->MarkReady(); 16228bf80f4bSopenharmony_ci } 16238bf80f4bSopenharmony_ci } 16248bf80f4bSopenharmony_ci return false; 16258bf80f4bSopenharmony_ci }), 16268bf80f4bSopenharmony_ci false); 16278bf80f4bSopenharmony_ci } 16288bf80f4bSopenharmony_ci } 16298bf80f4bSopenharmony_ci } 16308bf80f4bSopenharmony_ci return false; 16318bf80f4bSopenharmony_ci }), 16328bf80f4bSopenharmony_ci false); 16338bf80f4bSopenharmony_ci return ret; 16348bf80f4bSopenharmony_ci } 16358bf80f4bSopenharmony_ci return SCENE_NS::IRayCastResult::Ptr(); 16368bf80f4bSopenharmony_ci } 16378bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::Entity> RenderCameras() override 16388bf80f4bSopenharmony_ci { 16398bf80f4bSopenharmony_ci if (sceneHolder_) { 16408bf80f4bSopenharmony_ci return sceneHolder_->RenderCameras(); 16418bf80f4bSopenharmony_ci } 16428bf80f4bSopenharmony_ci return {}; 16438bf80f4bSopenharmony_ci } 16448bf80f4bSopenharmony_ci void ActivateCamera(const SCENE_NS::ICamera::Ptr& camera) override 16458bf80f4bSopenharmony_ci { 16468bf80f4bSopenharmony_ci if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 16478bf80f4bSopenharmony_ci auto ent = e->GetEntity(); 16488bf80f4bSopenharmony_ci sceneHolder_->ActivateCamera(ent); 16498bf80f4bSopenharmony_ci } 16508bf80f4bSopenharmony_ci } 16518bf80f4bSopenharmony_ci 16528bf80f4bSopenharmony_ci void DeactivateCamera(const SCENE_NS::ICamera::Ptr& camera) override 16538bf80f4bSopenharmony_ci { 16548bf80f4bSopenharmony_ci if (!camera) { 16558bf80f4bSopenharmony_ci return; 16568bf80f4bSopenharmony_ci } 16578bf80f4bSopenharmony_ci 16588bf80f4bSopenharmony_ci if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 16598bf80f4bSopenharmony_ci sceneHolder_->DeactivateCamera(e->GetEntity()); 16608bf80f4bSopenharmony_ci } 16618bf80f4bSopenharmony_ci } 16628bf80f4bSopenharmony_ci bool IsCameraActive(const SCENE_NS::ICamera::Ptr& camera) override 16638bf80f4bSopenharmony_ci { 16648bf80f4bSopenharmony_ci if (!camera) { 16658bf80f4bSopenharmony_ci return false; 16668bf80f4bSopenharmony_ci } 16678bf80f4bSopenharmony_ci 16688bf80f4bSopenharmony_ci if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 16698bf80f4bSopenharmony_ci return sceneHolder_->IsCameraActive(e->GetEntity()); 16708bf80f4bSopenharmony_ci } 16718bf80f4bSopenharmony_ci return false; 16728bf80f4bSopenharmony_ci } 16738bf80f4bSopenharmony_ci 16748bf80f4bSopenharmony_ciprivate: 16758bf80f4bSopenharmony_ci void SubscribeToPropertyChanges() 16768bf80f4bSopenharmony_ci { 16778bf80f4bSopenharmony_ci if (RootNode()) { 16788bf80f4bSopenharmony_ci rootNodeChangedToken_ = RootNode()->OnChanged()->AddHandler( 16798bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::IOnChanged>(this, &SceneImpl::OnRootNodeChanged)); 16808bf80f4bSopenharmony_ci } 16818bf80f4bSopenharmony_ci 16828bf80f4bSopenharmony_ci if (Uri()) { 16838bf80f4bSopenharmony_ci uriHandlerToken_ = Uri()->OnChanged()->AddHandler( 16848bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::IOnChanged>([this]() { this->Load(Uri()->GetValue()); })); 16858bf80f4bSopenharmony_ci } 16868bf80f4bSopenharmony_ci 16878bf80f4bSopenharmony_ci // Start listening changes of the scene controller properties. These may go to different place some day 16888bf80f4bSopenharmony_ci if (SystemGraphUri()) { 16898bf80f4bSopenharmony_ci systemGraphUriHandlerToken_ = SystemGraphUri()->OnChanged()->AddHandler( 16908bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::IOnChanged>(this, &SceneImpl::onSystemGraphUriChanged)); 16918bf80f4bSopenharmony_ci } 16928bf80f4bSopenharmony_ci } 16938bf80f4bSopenharmony_ci 16948bf80f4bSopenharmony_ci void UnsubscribeFromPropertyChanges() 16958bf80f4bSopenharmony_ci { 16968bf80f4bSopenharmony_ci if (Uri()) { 16978bf80f4bSopenharmony_ci Uri()->OnChanged()->RemoveHandler(uriHandlerToken_); 16988bf80f4bSopenharmony_ci uriHandlerToken_ = {}; 16998bf80f4bSopenharmony_ci } 17008bf80f4bSopenharmony_ci 17018bf80f4bSopenharmony_ci if (RootNode()) { 17028bf80f4bSopenharmony_ci RootNode()->OnChanged()->RemoveHandler(rootNodeChangedToken_); 17038bf80f4bSopenharmony_ci rootNodeChangedToken_ = {}; 17048bf80f4bSopenharmony_ci } 17058bf80f4bSopenharmony_ci 17068bf80f4bSopenharmony_ci if (SystemGraphUri()) { 17078bf80f4bSopenharmony_ci SystemGraphUri()->OnChanged()->RemoveHandler(systemGraphUriHandlerToken_); 17088bf80f4bSopenharmony_ci systemGraphUriHandlerToken_ = {}; 17098bf80f4bSopenharmony_ci } 17108bf80f4bSopenharmony_ci 17118bf80f4bSopenharmony_ci if (Asynchronous()) { 17128bf80f4bSopenharmony_ci Asynchronous()->OnChanged()->RemoveHandler(asyncChangedToken_); 17138bf80f4bSopenharmony_ci asyncChangedToken_ = {}; 17148bf80f4bSopenharmony_ci } 17158bf80f4bSopenharmony_ci } 17168bf80f4bSopenharmony_ci 17178bf80f4bSopenharmony_ci void OnRootNodeChanged() 17188bf80f4bSopenharmony_ci { 17198bf80f4bSopenharmony_ci auto contentObject = interface_pointer_cast<META_NS::IObject>(RootNode()->GetValue()); 17208bf80f4bSopenharmony_ci contentImpl_->SetContent(contentObject); 17218bf80f4bSopenharmony_ci 17228bf80f4bSopenharmony_ci META_NS::HierarchyChangeModeValue changeMode; 17238bf80f4bSopenharmony_ci changeMode.Set(META_NS::HierarchyChangeMode::NOTIFY_CONTAINER); 17248bf80f4bSopenharmony_ci hierarchyController_->SetTarget(contentObject, changeMode); 17258bf80f4bSopenharmony_ci } 17268bf80f4bSopenharmony_ci 17278bf80f4bSopenharmony_ci META_NS::IEvent::Token systemGraphUriHandlerToken_ {}; 17288bf80f4bSopenharmony_ci META_NS::IEvent::Token renderSizeHandlerToken_ {}; 17298bf80f4bSopenharmony_ci META_NS::IEvent::Token cameraHandlerToken_ {}; 17308bf80f4bSopenharmony_ci META_NS::IEvent::Token uriHandlerToken_ {}; 17318bf80f4bSopenharmony_ci META_NS::IEvent::Token rootNodeChangedToken_ {}; 17328bf80f4bSopenharmony_ci META_NS::IEvent::Token renderModeChangedToken_ {}; 17338bf80f4bSopenharmony_ci META_NS::IEvent::Token asyncChangedToken_ {}; 17348bf80f4bSopenharmony_ci 17358bf80f4bSopenharmony_ci SceneHolder::Ptr sceneHolder_; 17368bf80f4bSopenharmony_ci 17378bf80f4bSopenharmony_ci BASE_NS::string rootNodeId_; 17388bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::INode::Ptr> nodes_; 17398bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::ICamera::WeakPtr> cameras_; 17408bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMesh::WeakPtr> meshes_; 17418bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMaterial::WeakPtr> materials_; 17428bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, META_NS::IAnimation::WeakPtr> animations_; 17438bf80f4bSopenharmony_ci 17448bf80f4bSopenharmony_ci BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMaterial::WeakPtr> uriMaterials_; 17458bf80f4bSopenharmony_ci 17468bf80f4bSopenharmony_ci uint64_t instanceNumber_ { 0 }; 17478bf80f4bSopenharmony_ci 17488bf80f4bSopenharmony_ci // Preserve property instances while scene / ecs is invalid 17498bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr rootNodePtr_ {}; 17508bf80f4bSopenharmony_ci SCENE_NS::ICamera::Ptr cameraNodePtr_ {}; 17518bf80f4bSopenharmony_ci META_NS::IContent::Ptr contentImpl_ {}; 17528bf80f4bSopenharmony_ci 17538bf80f4bSopenharmony_ci uint64_t defaultCameraHandle_ { 0 }; 17548bf80f4bSopenharmony_ci 17558bf80f4bSopenharmony_ci // We need to add a node onto a container in bit awkward position (without exposing it to a public api) 17568bf80f4bSopenharmony_ci // Store it here. 17578bf80f4bSopenharmony_ci SCENE_NS::INode::Ptr currentParent_ {}; 17588bf80f4bSopenharmony_ci META_NS::IObjectHierarchyObserver::Ptr hierarchyController_; 17598bf80f4bSopenharmony_ci 17608bf80f4bSopenharmony_ci META_NS::IAnimationController::Ptr animationController_; 17618bf80f4bSopenharmony_ci}; 17628bf80f4bSopenharmony_ci 17638bf80f4bSopenharmony_ciBASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> SceneImpl::GetAnimations() const 17648bf80f4bSopenharmony_ci{ 17658bf80f4bSopenharmony_ci return animationController_->GetAnimations(); 17668bf80f4bSopenharmony_ci} 17678bf80f4bSopenharmony_ciBASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> SceneImpl::GetRunning() const 17688bf80f4bSopenharmony_ci{ 17698bf80f4bSopenharmony_ci return animationController_->GetRunning(); 17708bf80f4bSopenharmony_ci} 17718bf80f4bSopenharmony_cibool SceneImpl::AddAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) 17728bf80f4bSopenharmony_ci{ 17738bf80f4bSopenharmony_ci return animationController_->AddAnimation(animation); 17748bf80f4bSopenharmony_ci} 17758bf80f4bSopenharmony_cibool SceneImpl::RemoveAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) 17768bf80f4bSopenharmony_ci{ 17778bf80f4bSopenharmony_ci return animationController_->RemoveAnimation(animation); 17788bf80f4bSopenharmony_ci} 17798bf80f4bSopenharmony_civoid SceneImpl::Clear() 17808bf80f4bSopenharmony_ci{ 17818bf80f4bSopenharmony_ci animationController_->Clear(); 17828bf80f4bSopenharmony_ci} 17838bf80f4bSopenharmony_ciMETA_NS::IAnimationController::StepInfo SceneImpl::Step(const META_NS::IClock::ConstPtr& clock) 17848bf80f4bSopenharmony_ci{ 17858bf80f4bSopenharmony_ci return animationController_->Step(clock); 17868bf80f4bSopenharmony_ci} 17878bf80f4bSopenharmony_ci 17888bf80f4bSopenharmony_ci} // namespace 17898bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE() 17908bf80f4bSopenharmony_civoid RegisterSceneImpl() 17918bf80f4bSopenharmony_ci{ 17928bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().RegisterObjectType<SceneImpl>(); 17938bf80f4bSopenharmony_ci} 17948bf80f4bSopenharmony_civoid UnregisterSceneImpl() 17958bf80f4bSopenharmony_ci{ 17968bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().UnregisterObjectType<SceneImpl>(); 17978bf80f4bSopenharmony_ci} 17988bf80f4bSopenharmony_ciSCENE_END_NAMESPACE() 1799