1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include <algorithm> 16#include <functional> 17#include <scene_plugin/api/camera_uid.h> 18#include <scene_plugin/api/environment_uid.h> 19#include <scene_plugin/api/light_uid.h> 20#include <scene_plugin/api/material_uid.h> 21#include <scene_plugin/api/mesh_uid.h> 22#include <scene_plugin/api/node_uid.h> 23#include <scene_plugin/api/scene_uid.h> 24#include <scene_plugin/api/view_node_uid.h> 25#include <scene_plugin/interface/intf_ecs_scene.h> 26#include <scene_plugin/interface/intf_environment.h> 27 28#include <3d/ecs/systems/intf_node_system.h> 29#include <core/io/intf_file_manager.h> 30 31#include <meta/api/event_handler.h> 32#include <meta/ext/object_container.h> 33#include <meta/interface/animation/intf_animation_controller.h> 34#include <meta/interface/intf_content.h> 35#include <meta/interface/intf_named.h> 36#include <meta/interface/intf_object_hierarchy_observer.h> 37#include <meta/interface/serialization/intf_importer.h> 38 39#include "intf_node_private.h" 40#include "intf_resource_private.h" 41#include "scene_holder.h" 42#include "task_utils.h" 43 44// "synchronously initialize the nodes from main scene file when the scene is loaded 45 46// Save the project .scene file when scene object is being serialized. In practice this may override the changes on 47// scene file from other sources. To be rectified further 48 49// Name prefab instances with IObject::GetUid(). The other option is to use fixed "prefab_instance_NN" with running 50// instance number. The latter may cause trouble with .scene-files if it contains previous instances 51 52using SCENE_NS::MakeTask; 53namespace { 54class NotifyOnExit { 55public: 56 explicit NotifyOnExit(bool notify, std::function<void()> callback) : notify_(notify), callback_(callback) {} 57 virtual ~NotifyOnExit() 58 { 59 if (notify_) { 60 callback_(); 61 } 62 } 63 bool notify_; 64 std::function<void()> callback_; 65}; 66 67class SceneImpl final : public META_NS::ObjectContainerFwd<SceneImpl, SCENE_NS::ClassId::Scene, SCENE_NS::IScene, 68 SCENE_NS::IEcsScene, META_NS::IContent, META_NS::IAnimationController> { 69 /// Add the animation controller stuff here. (as scene should be the controller of it's animations) 70 META_FORWARD_READONLY_PROPERTY(uint32_t, Count, animationController_->Count()) 71 META_FORWARD_READONLY_PROPERTY(uint32_t, RunningCount, animationController_->RunningCount()) 72 73 BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> GetAnimations() const override; 74 BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> GetRunning() const override; 75 bool AddAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) override; 76 bool RemoveAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) override; 77 void Clear() override; 78 StepInfo Step(const META_NS::IClock::ConstPtr& clock) override; 79 // now back to normal scene impl 80 81 META_IMPLEMENT_INTERFACE_PROPERTY(META_NS::INamed, BASE_NS::string, Name, {}) 82 META_IMPLEMENT_INTERFACE_PROPERTY( 83 SCENE_NS::IScene, BASE_NS::string, SystemGraphUri, "project://assets/config/system_graph.json") 84 META_IMPLEMENT_INTERFACE_READONLY_PROPERTY( 85 SCENE_NS::IScene, uint32_t, Status, SCENE_STATUS_UNINITIALIZED, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 86 META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IScene, SCENE_NS::INode::Ptr, RootNode, {}) 87 META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, SCENE_NS::ICamera::Ptr, DefaultCamera, {}) 88 META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, BASE_NS::string, Uri, {}) 89 META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, bool, Asynchronous, false) 90 META_IMPLEMENT_INTERFACE_ARRAY_PROPERTY(SCENE_NS::IScene, SCENE_NS::IMaterial::Ptr, Materials, {}) 91 META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IScene, SCENE_NS::IRenderConfiguration::Ptr, RenderConfiguration, {}) 92 93 META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnLoaded) 94 META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IEcsScene, uint8_t, RenderMode, SCENE_NS::IEcsScene::RENDER_IF_DIRTY) 95 96 META_FORWARD_READONLY_PROPERTY(IObject::Ptr, Content, (contentImpl_ ? contentImpl_->Content() : nullptr)) 97 META_FORWARD_PROPERTY(bool, ContentSearchable, (contentImpl_ ? contentImpl_->ContentSearchable() : nullptr)) 98 META_FORWARD_PROPERTY( 99 META_NS::IContentLoader::Ptr, ContentLoader, (contentImpl_ ? contentImpl_->ContentLoader() : nullptr)) 100 101 void SetRenderMode() 102 { 103 AddEngineTask(MakeTask( 104 [renderMode = META_NS::GetValue(RenderMode())](auto sceneHolder) { 105 sceneHolder->SetRenderMode(renderMode); 106 return false; 107 }, 108 sceneHolder_), 109 false); 110 } 111 112 uint64_t GetCameraHandle(const SCENE_NS::ICamera::Ptr& camera) 113 { 114 if (camera) { 115 auto ecsObject = interface_pointer_cast<SCENE_NS::IEcsObject>(camera); 116 if (ecsObject) { 117 return ecsObject->GetEntity().id; 118 } 119 } 120 121 return SCENE_NS::IScene::DEFAULT_CAMERA; 122 } 123 124 struct BitmapInfo { 125 BitmapInfo() = default; 126 BitmapInfo(SCENE_NS::IBitmap::Ptr bmp) : bitmap(bmp) {} 127 BASE_NS::Math::UVec2 size {}; 128 SCENE_NS::IBitmap::Ptr bitmap {}; 129 META_NS::EventHandler bitmapChanged {}; 130 }; 131 BASE_NS::unordered_map<uint64_t, BitmapInfo> bitmaps_; 132 BitmapInfo& GetData(const SCENE_NS::ICamera::Ptr& camera) 133 { 134 auto cameraHandle = GetCameraHandle(camera); 135 if (cameraHandle == SCENE_NS::IScene::DEFAULT_CAMERA) { 136 cameraHandle = defaultCameraHandle_; 137 } 138 auto handle = cameraHandle; 139 if (cameraHandle == SCENE_NS::IScene::DEFAULT_CAMERA && !bitmaps_.empty()) { 140 handle = defaultCameraHandle_; 141 } 142 return bitmaps_[handle]; 143 } 144 145 void SetBitmap(const SCENE_NS::IBitmap::Ptr& bitmap, const SCENE_NS::ICamera::Ptr& camera) override 146 { 147 BitmapInfo& data = GetData(camera); 148 auto uiBitmap = interface_pointer_cast<SCENE_NS::IBitmap>(bitmap); 149 if (!uiBitmap) { 150 // disable bitmap override. 151 data.bitmapChanged.Unsubscribe(); 152 data.bitmap = {}; 153 sceneHolder_->SetCameraTarget(camera, data.size, {}); 154 return; 155 } 156 157 data.bitmap = uiBitmap; 158 data.size = data.bitmap->Size()->GetValue(); 159 const auto rh = data.bitmap->GetRenderHandle(); 160 161 data.bitmapChanged.Subscribe( 162 uiBitmap->ResourceChanged(), META_NS::MakeCallback<META_NS::IOnChanged>([this, camera]() { 163 BitmapInfo& data = GetData(camera); 164 data.size = data.bitmap->Size()->GetValue(); 165 const auto rh = data.bitmap->GetRenderHandle(); 166 sceneHolder_->SetCameraTarget(camera, data.size, rh); 167 })); 168 169 META_NS::Invoke<META_NS::IOnChanged>(uiBitmap->ResourceChanged()); 170 } 171 172 SCENE_NS::IBitmap::Ptr GetBitmap(bool notifyFrameDrawn, const SCENE_NS::ICamera::Ptr& camera) override 173 { 174 BitmapInfo& data = GetData(camera); 175 if (!data.bitmap) { 176 // there is no bitmap for this. 177 // create it? 178 } 179 return data.bitmap; 180 } 181 182#define CREATE_META_INSTANCE(type, name) GetObjectRegistry().Create<META_NS::type>(META_NS::ClassId::name) 183 184 // META_NS::IContent 185 bool SetContent(const META_NS::IObject::Ptr& content) override 186 { 187 // Should be no-op because the Root Node of a scene (content in this case) can be assigned only if the scene was 188 // reloaded. 189 return false; 190 } 191 192 bool Build(const META_NS::IMetadata::Ptr& data) override 193 { 194 auto& registry = GetObjectRegistry(); 195 196 animationController_ = registry.Create<META_NS::IAnimationController>(META_NS::ClassId::AnimationController); 197 198 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>; 199 BASE_NS::shared_ptr<RENDER_NS::IRenderContext> rc; 200 META_NS::ITaskQueue::Ptr appQueue; 201 META_NS::ITaskQueue::Ptr engineQueue; 202 203 if (data) { 204 if (auto prp = data->GetPropertyByName<IntfPtr>("RenderContext")) { 205 rc = interface_pointer_cast<RENDER_NS::IRenderContext>(prp->GetValue()); 206 } 207 if (auto prp = data->GetPropertyByName<IntfPtr>("EngineQueue")) { 208 engineQueue = interface_pointer_cast<META_NS::ITaskQueue>(prp->GetValue()); 209 } 210 if (auto prp = data->GetPropertyByName<IntfPtr>("AppQueue")) { 211 appQueue = interface_pointer_cast<META_NS::ITaskQueue>(prp->GetValue()); 212 } 213 } 214 if ((!rc) || (!engineQueue) || (!appQueue)) { 215 return false; 216 } 217 218 hierarchyController_ = 219 registry.Create<META_NS::IObjectHierarchyObserver>(SCENE_NS::ClassId::NodeHierarchyController); 220 221 contentImpl_ = registry.Create<META_NS::IContent>(META_NS::ClassId::ContentObject); 222 if (const auto req = interface_cast<META_NS::IRequiredInterfaces>(contentImpl_)) { 223 req->SetRequiredInterfaces({ SCENE_NS::INode::UID }); 224 } 225 226 sceneHolder_.reset(new SceneHolder(GetInstanceId(), registry, rc, appQueue, engineQueue)); 227 sceneHolder_->SetOperationMode(Asynchronous()->GetValue()); 228 229 asyncChangedToken_ = Asynchronous()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>( 230 [](const auto& sceneHolder, const auto& async) { 231 if (sceneHolder && async) { 232 sceneHolder->SetOperationMode(async->GetValue()); 233 } 234 }, 235 sceneHolder_, Asynchronous())); 236 237 renderModeChangedToken_ = RenderMode()->OnChanged()->AddHandler( 238 META_NS::MakeCallback<META_NS::IOnChanged>([weak = BASE_NS::weak_ptr(GetSelf())]() { 239 if (auto self = static_pointer_cast<SceneImpl>(weak.lock())) { 240 self->SetRenderMode(); 241 } 242 })); 243 244 sceneHolder_->SetInitializeCallback( 245 META_NS::MakeCallback<SceneHolder::ISceneInitialized>( 246 [me = BASE_NS::weak_ptr(GetSelf())](const BASE_NS::string& rootId, const BASE_NS::string& cameraId) { 247 if (auto self = me.lock().get()) 248 static_cast<SceneImpl*>(self)->onSceneInitialized(rootId, cameraId); 249 }), 250 sceneHolder_); 251 sceneHolder_->SetSceneLoadedCallback( 252 META_NS::MakeCallback<SceneHolder::ISceneLoaded>([me = BASE_NS::weak_ptr(GetSelf())](uint32_t status) { 253 if (auto self = me.lock().get()) 254 static_cast<SceneImpl*>(self)->OnSceneLoaded(status); 255 }), 256 sceneHolder_); 257 258 sceneHolder_->Initialize(sceneHolder_); 259 sceneHolder_->SetSystemGraphUri(META_NS::GetValue(SystemGraphUri())); 260 SubscribeToPropertyChanges(); 261 262 return true; 263 } 264 265 // this is not usually needed as explicit action, but the scene will pickup changes from 266 // ScenePresenters on the fly 267 void OnCameraChanged() 268 { 269 // Async, sceneholder takes over 270 if (sceneHolder_) { 271 sceneHolder_->ChangeCamera(META_ACCESS_PROPERTY(DefaultCamera)->GetValue()); 272 } 273 } 274 275 // Async, sceneholder takes over 276 BASE_NS::vector<META_NS::IAnimation::Ptr> allAnims_; 277 BASE_NS::vector<META_NS::IAnimation::Ptr> GetAnimations() override 278 { 279 // adds/removes animations to cache.. 280 auto tmp = allAnims_; 281 allAnims_.clear(); 282 for (auto anim : sceneHolder_->GetAnimations()) { 283 if (auto i = interface_cast<META_NS::IObject>(anim)) { 284 auto name = i->GetName(); 285 286 size_t ix = 0; 287 if (!RollOverPrefix(ix, name, ANIMATIONS_PREFIX)) { 288 continue; 289 } 290 291 // check cache 292 META_NS::IAnimation::Ptr rn; 293 auto subname = name.substr(ix); 294 for (auto& a : tmp) { 295 if (interface_cast<META_NS::IObject>(a)->GetName() == subname) { 296 rn = a; 297 break; 298 } 299 } 300 if (!rn) { 301 rn = interface_pointer_cast<META_NS::IAnimation>( 302 CreateNode(name.substr(ix), false, SCENE_NS::ClassId::Animation.Id(), 303 SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 304 } 305 306 allAnims_.push_back(rn); 307 } 308 } 309 return allAnims_; 310 } 311 312 META_NS::IAnimation::Ptr GetAnimation(const BASE_NS::string_view name) override 313 { 314#ifndef USE_DIRECT_ECS_ANIMATION 315 316 size_t ix = 0; 317 if (!RollOverPrefix(ix, name, ANIMATIONS_PREFIX)) { 318 return { nullptr }; 319 } 320 321 // check cache 322 if (auto it = animations_.find(name.substr(ix)); it != animations_.end()) { 323 if (auto animation = it->second.lock()) { 324 return animation; 325 } 326 } 327 // Create EcsObject. When running asynchronously, we have no way of knowing if we can rely that existing 328 // animation will be found 329 auto anim = interface_pointer_cast<META_NS::IAnimation>(CreateNode(name.substr(ix), false, 330 SCENE_NS::ClassId::Animation.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 331 332 return anim; 333#else 334 auto ecsAnimation = sceneHolder_->GetAnimation(BASE_NS::string(name.data(), name.size())); 335 336 if (!ecsAnimation) { 337 ecsAnimation = GetObjectRegistry().Create<SCENE_NS::IEcsAnimation>(SCENE_NS::ClassId::EcsAnimation); 338 AddEngineTask( 339 META_NS::MakeCallable<META_NS::ITaskQueueTask>( 340 [ecsAnimation, nameString = BASE_NS::string(name.data(), name.size()), 341 weak = BASE_NS::weak_ptr(sceneHolder_)]() { 342 if (auto sceneHolder = weak.lock()) { 343 CORE_NS::Entity entity; 344 if (sceneHolder->FindAnimation(nameString, entity)) { 345 if (auto ecsProxyIf = interface_pointer_cast<SCENE_NS::IEcsProxyObject>(ecsAnimation)) { 346 ecsProxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener()); 347 } 348 ecsAnimation->SetEntity(*sceneHolder->GetEcs(), entity); 349 } 350 } 351 return false; 352 }), 353 false); 354 } 355 META_ACCESS_PROPERTY(Animations)->Get()->Add(ecsAnimation); 356 357 return interface_pointer_cast<META_NS::IAnimation>(ecsAnimation); 358#endif 359 } 360 361 void CreateEmpty() override 362 { 363 Load("scene://empty"); 364 } 365 366 bool Load(const BASE_NS::string_view uri) override 367 { 368 if (!Name()->IsValueSet()) { 369 SetValue(Name(), "Scene"); 370 } 371 372 if (!uri.empty()) { 373 META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_LOADING); 374 sceneHolder_->Load(BASE_NS::string(uri.data(), uri.size())); 375 return true; 376 } 377 return false; 378 } 379 380 void onSystemGraphUriChanged() 381 { 382 META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_LOADING); 383 sceneHolder_->SetSystemGraphUri(META_NS::GetValue(SystemGraphUri())); 384 } 385 386 void SetRenderSize(uint32_t width, uint32_t height, const SCENE_NS::ICamera::Ptr& camera) override 387 { 388 if (camera) { 389 camera->SetDefaultRenderTargetSize(width, height); 390 } else if (auto defaultCamera = META_NS::GetValue(DefaultCamera())) { 391 defaultCamera->SetDefaultRenderTargetSize(width, height); 392 } 393 } 394 395 SCENE_NS::INode::Ptr GetNode(const BASE_NS::string_view path, const BASE_NS::Uid classId, 396 SCENE_NS::INode::BuildBehavior buildBehavior) override 397 { 398 return GetNodeRecursive(path, classId, true, buildBehavior); 399 } 400 401 META_NS::ObjectId ResolveNodeTypeFromPath(const BASE_NS::string_view patchedPath, bool isNodeType) 402 { 403 // This is best effort 404 // We cannot determine the type unless ECS has probed the component 405 406 // This kind of introspection may cause materials and meshes to be treated as nodes 407 // which kind of contradicts with their normal use through API 408 auto ecs = GetEcs(); 409 CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*ecs); 410 const auto& root = nodeSystem.GetRootNode(); 411 412 const auto& ecsNode = root.LookupNodeByPath(patchedPath); 413 CORE_NS::Entity entity {}; 414 if (ecsNode) { 415 entity = ecsNode->GetEntity(); 416 } else { 417 CORE_LOG_W("%s:No entity for %s, type info not available", __func__, BASE_NS::string(patchedPath).c_str()); 418 CORE_LOG_W("If you know the expected type, consider using a template or providing the class id"); 419 } 420 421 // shadow camera could provide false positive, so order matters 422 if (auto lightManager = ecs->GetComponentManager(CORE3D_NS::ILightComponentManager::UID)) { 423 if (lightManager->HasComponent(entity)) { 424 return SCENE_NS::ClassId::Light; 425 } 426 } 427 428 if (auto cameraManager = ecs->GetComponentManager(CORE3D_NS::ICameraComponentManager::UID)) { 429 if (cameraManager->HasComponent(entity)) { 430 return SCENE_NS::ClassId::Camera; 431 } 432 } 433 434 if (auto envManager = ecs->GetComponentManager(CORE3D_NS::IEnvironmentComponentManager::UID)) { 435 if (envManager->HasComponent(entity)) { 436 return SCENE_NS::ClassId::Environment; 437 } 438 } 439 440 if (!isNodeType) { 441 if (auto nodeManager = ecs->GetComponentManager(CORE3D_NS::INodeComponentManager::UID)) { 442 // quirk, prefer nodes with node component treated as node) 443 if (!nodeManager->HasComponent(entity)) { 444 if (auto meshManager = ecs->GetComponentManager(CORE3D_NS::IMeshComponentManager::UID)) { 445 if (meshManager->HasComponent(entity)) { 446 return SCENE_NS::ClassId::Mesh; 447 } 448 } 449 if (auto materialManager = ecs->GetComponentManager(CORE3D_NS::IMaterialComponentManager::UID)) { 450 if (materialManager->HasComponent(entity)) { 451 return SCENE_NS::ClassId::Material; 452 } 453 } 454 } 455 } 456 } 457 458 return SCENE_NS::ClassId::Node; 459 } 460 461 SCENE_NS::INode::Ptr GetNodeRecursive(const BASE_NS::string_view path, const META_NS::ObjectId classId, 462 bool recurse, SCENE_NS::INode::BuildBehavior buildBehavior) 463 { 464 if (path.empty() || path == "/") { 465 return SCENE_NS::INode::Ptr {}; 466 } 467 468 BASE_NS::string patchedPath = recurse ? NormalizePath(path) : BASE_NS::string(path.data(), path.size()); 469 if (auto ite = nodes_.find(patchedPath) != nodes_.cend()) { 470 return nodes_[patchedPath]; 471 } 472 473 // ensure parent objects exist 474 if (recurse) { 475 size_t ix = patchedPath.find('/', 1); 476 while (BASE_NS::string_view::npos != ix) { 477 auto substr = patchedPath.substr(0, ix); 478 // When we traverse up the tree, we must ensure that the object is a node. 479 currentParent_ = GetNodeRecursive(substr, SCENE_NS::INode::UID, false, buildBehavior); 480 ++ix; 481 ix = patchedPath.find('/', ix); 482 } 483 } 484 485 auto ecs = GetEcs(); 486 META_NS::ObjectId implementationId = SCENE_NS::ClassId::Node; 487 488 bool isNodeType = (classId == SCENE_NS::INode::UID); 489 if ((classId == META_NS::IObject::UID || isNodeType) && ecs) { 490 implementationId = ResolveNodeTypeFromPath(patchedPath, isNodeType); 491 492 } else { 493 implementationId = classId; 494 } 495 496 auto node = CreateNode(patchedPath, false, implementationId, buildBehavior); 497 498 currentParent_ = {}; 499 return node; // finalInterface; 500 } 501 502 void RemoveNodeFromCurrentContainer(SCENE_NS::INode::Ptr& node) 503 { 504 if (auto containable = interface_cast<META_NS::IContainable>(node)) { 505 if (auto parent = interface_pointer_cast<META_NS::IContainer>(containable->GetParent())) { 506 parent->Remove(node); 507 } 508 } 509 } 510 511 bool RollOverPrefix(size_t& ix, const BASE_NS::string_view& name, const BASE_NS::string_view& prefix) 512 { 513 while (ix < name.length() && name[ix] == '/') { 514 ix++; 515 } 516 517 if (name.substr(ix).find(prefix) == 0) { 518 ix += prefix.length(); 519 } 520 521 while (ix < name.length() && name[ix] == '/') { 522 ix++; 523 } 524 525 return ix < name.length(); 526 } 527 528 void AddMaterial(SCENE_NS::IMaterial::Ptr material) override 529 { 530 auto materials = Materials()->GetValue(); 531 auto it = std::find(materials.begin(), materials.end(), material); 532 if (it != materials.end()) { 533 // Already exists. 534 CORE_LOG_D("Trying to add same material to scene multiple times."); 535 return; 536 } 537 538 Materials()->AddValue(material); 539 UpdateCachedReference(interface_pointer_cast<SCENE_NS::INode>(material)); 540 } 541 542 void RemoveMaterial(SCENE_NS::IMaterial::Ptr material) override 543 { 544 auto lock = Materials().GetLockedAccess(); 545 auto vec = lock->GetValue(); 546 for (size_t index = 0; index != vec.size(); ++index) { 547 if (vec[index] == material) { 548 lock->RemoveAt(index); 549 break; 550 } 551 } 552 553 for (auto&& ite : materials_) { 554 if (ite.second.lock() == material) { 555 ReleaseMaterial(ite.first); 556 break; 557 } 558 } 559 } 560 561 BASE_NS::vector<SCENE_NS::ICamera::Ptr> GetCameras() const override 562 { 563 BASE_NS::vector<SCENE_NS::ICamera::Ptr> result; 564 for (auto c : cameras_) { 565 if (auto cam = c.second.lock()) { 566 result.push_back(cam); 567 } 568 } 569 return result; 570 } 571 572 BASE_NS::vector<SCENE_NS::IMaterial::Ptr> GetMaterials() const override 573 { 574 BASE_NS::vector<SCENE_NS::IMaterial::Ptr> result; 575 for (auto& material : materials_) { 576 auto ptr = material.second.lock(); 577 if (ptr) { 578 result.push_back(ptr); 579 } 580 } 581 582 return result; 583 } 584 585 // Returns a material from the scene with a given path 586 SCENE_NS::IMaterial::Ptr GetMaterial(const BASE_NS::string_view name) override 587 { 588 // The material file, aka uri-path is somewhat parallel due ownership is different for uri-materials 589 // however, one can claim traditional handle and have them preserved 590 // through flat cache. Should be consolidated someday. 591 if (name.find("://") != BASE_NS::string_view::npos) { 592 return GetOrLoadMaterial(name); 593 } 594 595 size_t ix = 0; 596 if (!RollOverPrefix(ix, name, MATERIALS_PREFIX)) { 597 return { nullptr }; 598 } 599 600 // check cache (first with name:entityid) 601 if (auto it = materials_.find(name.substr(ix)); it != materials_.end()) { 602 if (auto material = it->second.lock()) { 603 return material; 604 } 605 } 606 607 // check cache (direct material name) 608 for (auto entry : materials_) { 609 auto material = entry.second.lock(); 610 if (auto node = interface_pointer_cast<SCENE_NS::INode>(material)) { 611 if (node->Name()->GetValue() == name) { 612 return material; 613 } 614 } 615 } 616 617 if (auto it = materials_.find(name.substr(ix)); it != materials_.end()) { 618 if (auto material = it->second.lock()) { 619 return material; 620 } 621 } 622 623 // Create EcsObject. When running asynchronously, we have no way of knowing if we should create 624 // new node or just rely that existing will be found 625 auto mat = interface_pointer_cast<SCENE_NS::IMaterial>(CreateNode(name.substr(ix), false, 626 SCENE_NS::ClassId::Material.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 627 628 return mat; 629 } 630 631 BASE_NS::vector<SCENE_NS::IMesh::Ptr> GetMeshes() const override 632 { 633 BASE_NS::vector<SCENE_NS::IMesh::Ptr> result; 634 for (auto mesh : meshes_) { 635 auto ptr = mesh.second.lock(); 636 if (ptr) { 637 result.push_back(ptr); 638 } 639 } 640 641 return result; 642 } 643 644 // Returns a material from the scene with a given name 645 SCENE_NS::IMesh::Ptr GetMesh(const BASE_NS::string_view name) override 646 { 647 size_t ix = 0; 648 if (!RollOverPrefix(ix, name, MESHES_PREFIX)) { 649 return { nullptr }; 650 } 651 652 // check cache 653 if (auto it = meshes_.find(name.substr(ix)); it != meshes_.end()) { 654 if (auto mesh = it->second.lock()) { 655 return mesh; 656 } 657 } 658 // Create EcsObject. When running asynchronously, we have no way of knowing if we should create 659 // new node or just rely that existing will be found 660 auto mesh = interface_pointer_cast<SCENE_NS::IMesh>(CreateNode(name.substr(ix), false, 661 SCENE_NS::ClassId::Mesh.Id(), SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 662 663 return mesh; 664 } 665 666 BASE_NS::string constructPath(CORE_NS::Entity ent) const 667 { 668 auto ecs = GetEcs(); 669 auto* nodeManager = CORE_NS::GetManager<CORE3D_NS::INodeComponentManager>(*ecs); 670 auto* nameManager = CORE_NS::GetManager<CORE3D_NS::INameComponentManager>(*ecs); 671 BASE_NS::string path; 672 if (nodeManager && nameManager) { 673 auto curent = ent; 674 for (;;) { 675 if (!CORE_NS::EntityUtil::IsValid(curent)) { 676 // Reached root. 677 break; 678 } 679 if (!nodeManager->HasComponent(curent)) { 680 // not a node? 681 return ""; 682 } 683 if (!nameManager->HasComponent(curent)) { 684 // no name in hierarchy. "fail"? or generate "name" for path.. 685 return ""; 686 } 687 auto namecomp = nameManager->Get(curent); 688 if (!path.empty()) { 689 path.insert(0, "/"); 690 } 691 path.insert(0, namecomp.name.c_str()); 692 const auto& node = nodeManager->Get(curent); 693 curent = node.parent; 694 } 695 } 696 if (!path.empty()) { 697 path.insert(0, "/"); 698 } 699 return path; 700 } 701 // Implementation for scene change callbacks. 702 // The tricky bit here is that we may have placeholders on containers that may have received serialized data 703 // during construction, so we just cannot replace those, but need to rebind them instead 704 void onSceneInitialized(const BASE_NS::string& rootId, const BASE_NS::string& cameraId) 705 { 706 // Set root node 707 rootNodeId_ = rootId; 708 auto rootIdNormalized = NormalizePath(rootNodeId_); 709 710 if (rootNodePtr_) { 711 // check if someone assigned us a root node while we are preserving the previous one 712 if (!META_ACCESS_PROPERTY(RootNode)->GetValue()) { 713 META_ACCESS_PROPERTY(RootNode)->SetValue(rootNodePtr_); 714 } 715 rootNodePtr_.reset(); 716 } 717 718 if (cameraNodePtr_) { 719 // check if someone assigned us a root node while we are preserving the previous one 720 if (!META_ACCESS_PROPERTY(DefaultCamera)->GetValue()) { 721 META_ACCESS_PROPERTY(DefaultCamera)->SetValue(cameraNodePtr_); 722 } 723 cameraNodePtr_.reset(); 724 } 725 726 if (auto renderConfiguration = META_NS::GetValue(RenderConfiguration())) { 727 // Ensure the render configuration is bound to scene. 728 auto resource = interface_pointer_cast<IResourcePrivate>(renderConfiguration); 729 if (resource) { 730 resource->Connect(sceneHolder_); 731 } 732 } 733 734 // setup subscription for toolkit changes 735 RenderConfiguration()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() { 736 auto resource = interface_pointer_cast<IResourcePrivate>(GetValue(RenderConfiguration())); 737 if (resource) { 738 resource->Connect(sceneHolder_); 739 } 740 }), 741 reinterpret_cast<uint64_t>(this)); 742 743 if (auto rootNode = META_ACCESS_PROPERTY(RootNode)->GetValue()) { 744 // switch new ecsObject 745 BindNodeToEcs(rootNode, rootIdNormalized, false); 746 nodes_[rootIdNormalized] = rootNode; 747 } else { 748 META_ACCESS_PROPERTY(RootNode)->SetValue(GetSelf<SCENE_NS::IScene>()->GetNode<SCENE_NS::INode>(rootId)); 749 } 750 751 auto defaultCamera = META_ACCESS_PROPERTY(DefaultCamera)->GetValue(); 752 if (!defaultCamera) { 753 defaultCamera = GetSelf<SCENE_NS::IScene>()->GetNode<SCENE_NS::ICamera>(cameraId); 754 META_ACCESS_PROPERTY(DefaultCamera)->SetValue(defaultCamera); 755 } 756 757 if (defaultCamera) { 758 ActivateCamera(defaultCamera); 759 } 760 761 // under normal conditions, this would take place asyncronously 762 // however, if we are running on synchronous mode we need to restore the ecs bindings here 763 for (auto& prevNode : nodes_) { 764 if (prevNode.first != rootIdNormalized && prevNode.first != cameraId) { 765 BindNodeToEcs(prevNode.second, prevNode.first, false); 766 } 767 } 768 769 // This is information only unless we instantiate all the scene nodes immediately 770 // Should be flagged more effectively on production builds 771 CORE3D_NS::INodeSystem& nodeSystem = *CORE_NS::GetSystem<CORE3D_NS::INodeSystem>(*GetEcs()); 772 const auto& root = nodeSystem.GetRootNode(); 773 774 instantiateNodes(root, "/"); 775 776 // notify observers about the change 777 META_ACCESS_PROPERTY(Status)->SetValue(SCENE_NS::IScene::SCENE_STATUS_READY); 778 META_NS::Invoke<META_NS::IOnChanged>(OnLoaded()); 779 780 sceneHolder_->SetUninitializeCallback( 781 META_NS::MakeCallback<SceneHolder::ISceneUninitialized>([me = BASE_NS::weak_ptr(GetSelf())]() { 782 if (auto self = me.lock().get()) 783 static_cast<SceneImpl*>(self)->DetachScene(); 784 }), 785 sceneHolder_); 786 } 787 788 void OnSceneLoaded(uint32_t status) 789 { 790 META_ACCESS_PROPERTY(Status)->SetValue(status); 791 if (status == SCENE_NS::IScene::SCENE_STATUS_READY) { 792 META_NS::Invoke<META_NS::IOnChanged>(OnLoaded()); 793 } 794 } 795 796 // Implementation for scene processing. 797 798 void DetachScene(bool setDirty = false) 799 { 800 if (META_ACCESS_PROPERTY(Status)) { 801 META_ACCESS_PROPERTY(Status)->SetValue(SCENE_STATUS_UNINITIALIZED); 802 } 803 804 cameras_.clear(); 805 materials_.clear(); 806 meshes_.clear(); 807 animations_.clear(); 808 nodes_.clear(); 809 810 // This effectively means that we keep the scene user objects forcibly live 811 // until we get fresh ones to replace them, not sure if that is intended 812 rootNodePtr_ = META_ACCESS_PROPERTY(RootNode)->GetValue(); 813 cameraNodePtr_ = META_ACCESS_PROPERTY(DefaultCamera)->GetValue(); 814 META_ACCESS_PROPERTY(RootNode)->SetValue({}); 815 META_ACCESS_PROPERTY(DefaultCamera)->SetValue({}); 816 817 if (setDirty) { 818 for (const auto& bitmap : bitmaps_) { 819 /*auto externalBitmap = interface_pointer_cast<UI_NS::ILume2DExternalBitmap>(bitmap.second.bitmap); 820 if (externalBitmap) { 821 externalBitmap->SetCoreBitmap(nullptr); 822 }*/ 823 bitmap.second.bitmap->SetRenderHandle({}, { 0, 0 }); 824 } 825 } 826 } 827 828 void instantiateNodes(const CORE3D_NS::ISceneNode& node, BASE_NS::string path) 829 { 830 if (!path.empty() && path.back() != '/') { 831 path.append("/"); 832 } 833 if (!node.GetName().empty()) { 834 path.append(node.GetName()); 835 } else { 836#ifndef INSTANTIATE_NODES_ON_INITIALIZE 837 path.append("["); 838 path.append(BASE_NS::to_string(node.GetEntity().id)); 839 path.append("]"); 840#endif 841 } 842 SCENE_PLUGIN_VERBOSE_LOG("%s", path.c_str()); 843#ifdef INSTANTIATE_NODES_ON_INITIALIZE 844 GetNode(path); 845#endif 846 847 for (const auto child : node.GetChildren()) 848 instantiateNodes(*child, path); 849 } 850 851 BASE_NS::string NormalizePath(const BASE_NS::string_view& path) 852 { 853 BASE_NS::string patchedPath; 854 if (path == rootNodeId_) { 855 patchedPath = path; 856 patchedPath.insert(0, "/"); 857 } else { 858 bool hasSlash = (path[0] == '/'); 859 if (path.compare(hasSlash ? 1 : 0, rootNodeId_.size(), rootNodeId_.data())) { 860 SCENE_PLUGIN_VERBOSE_LOG("%s: the path does not contain root node, patching the path", __func__); 861 patchedPath.append("/"); 862 patchedPath.append(rootNodeId_); 863 if (!hasSlash) { 864 patchedPath.append("/"); 865 } 866 patchedPath.append(path.data(), path.size()); 867 } else { 868 patchedPath = path; 869 if (!hasSlash) { 870 patchedPath = "/" + patchedPath; 871 } 872 } 873 } 874 return patchedPath; 875 } 876 877 SCENE_NS::IEcsObject::Ptr FindEcsObject(const BASE_NS::string_view& path, BASE_NS::string& patchedPath) 878 { 879 patchedPath = NormalizePath(path); 880 881 if (auto it = nodes_.find(patchedPath); it != nodes_.end()) { 882 return interface_pointer_cast<SCENE_NS::IEcsObject>(it->second); 883 } 884 return SCENE_NS::IEcsObject::Ptr {}; 885 } 886 887 SCENE_NS::IEcsObject::Ptr CreateNewEcsObject(const BASE_NS::string& /*path*/) 888 { 889 // Create new helper object 890 // Not much left here, could be presumably removed 891 auto ret = SCENE_NS::IEcsObject::Ptr {}; 892 893// Allow construction to progress even ecs was not available, 894// nodes will perform initialization asynchronously anyway 895 if (auto object = META_NS::GetObjectRegistry().Create(SCENE_NS::ClassId::EcsObject)) { 896 ret = interface_pointer_cast<SCENE_NS::IEcsObject>(object); 897 } 898 return ret; 899 } 900 901 SCENE_NS::IEcsObject::Ptr GetEcsObject(const BASE_NS::string_view& path) override 902 { 903 return interface_pointer_cast<SCENE_NS::IEcsObject>( 904 GetNode(path, META_NS::IObject::UID, SCENE_NS::INode::BuildBehavior::NODE_BUILD_CHILDREN_NO_BUILD)); 905 } 906 907 CORE_NS::IEcs::Ptr GetEcs() override 908 { 909 return sceneHolder_->GetEcs(); 910 } 911 912 CORE_NS::IEcs::Ptr GetEcs() const 913 { 914 return sceneHolder_->GetEcs(); 915 } 916 917 META_NS::ITaskQueue::Token AddEngineTask( 918 const META_NS::ITaskQueue::CallableType::Ptr& task, bool runDeferred) override 919 { 920 if (sceneHolder_) { 921 return sceneHolder_->QueueEngineTask(task, runDeferred); 922 } 923 return META_NS::ITaskQueue::Token {}; 924 } 925 926 META_NS::ITaskQueue::Token AddApplicationTask( 927 const META_NS::ITaskQueue::CallableType::Ptr& task, bool runDeferred) override 928 { 929 if (sceneHolder_) { 930 return sceneHolder_->QueueApplicationTask(task, runDeferred); 931 } 932 return META_NS::ITaskQueue::Token {}; 933 } 934 935 void CancelEngineTask(META_NS::ITaskQueue::Token token) override 936 { 937 if (sceneHolder_) { 938 return sceneHolder_->CancelEngineTask(token); 939 } 940 } 941 942 void CancelAppTask(META_NS::ITaskQueue::Token token) override 943 { 944 if (sceneHolder_) { 945 return sceneHolder_->CancelAppTask(token); 946 } 947 } 948 949 SCENE_NS::IEntityCollection* GetEntityCollection() override 950 { 951 if (sceneHolder_) { 952 return sceneHolder_->GetEntityCollection(); 953 } 954 955 return {}; 956 } 957 958 SCENE_NS::IAssetManager* GetAssetManager() override 959 { 960 if (sceneHolder_) { 961 return sceneHolder_->GetAssetManager(); 962 } 963 964 return {}; 965 } 966 967 SCENE_NS::IMaterial::Ptr GetOrLoadMaterial(BASE_NS::string_view uri) 968 { 969 // check cache 970 if (auto it = uriMaterials_.find(uri); it != uriMaterials_.end()) { 971 if (auto material = it->second.lock()) { 972 return material; 973 } 974 } 975 976 auto ret = LoadMaterial(uri); 977 uriMaterials_[uri] = ret; 978 return ret; 979 } 980 981 SCENE_NS::IMaterial::Ptr LoadMaterial(BASE_NS::string_view uri) override 982 { 983 bool isGltfUri = (uri.find(".glb/materials/") != BASE_NS::string_view::npos) || 984 (uri.find(".gltf/materials/") != BASE_NS::string_view::npos); 985 if (isGltfUri) { 986 auto resource = CreateResourceFromUri(SCENE_NS::ClassId::Material, uri); 987 if (resource) { 988 return interface_pointer_cast<SCENE_NS::IMaterial>(resource); 989 } 990 991 CORE_LOG_W("Could not resolve material URI: %s", BASE_NS::string(uri.data(), uri.size()).c_str()); 992 // we could return the control to CreateMaterial and let the engine resolve the materials with uri 993 // componenta as they seem to be in place when loaded from glb or gltf 994 } 995 996 SCENE_NS::IMaterial::Ptr ret; 997 998 return ret; 999 } 1000 1001 SCENE_NS::INode::Ptr CreateNode(const META_NS::ObjectId classId) 1002 { 1003 SCENE_NS::INode::Ptr node; 1004 1005 if (classId == SCENE_NS::ClassId::Light.Id() || classId == SCENE_NS::ILight::UID) { 1006 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Light); 1007 } else if (classId == SCENE_NS::ClassId::Camera.Id() || classId == SCENE_NS::ICamera::UID) { 1008 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Camera); 1009 } /*else if (classId == SCENE_NS::ClassId::ViewNode.Id() || classId == SCENE_NS::IViewNode::UID) { 1010 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::ViewNode); 1011 } */ 1012 else if (classId == SCENE_NS::ClassId::Material.Id() || classId == SCENE_NS::IMaterial::UID) { 1013 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Material); 1014 } else if (classId == SCENE_NS::ClassId::Mesh.Id() || classId == SCENE_NS::IMesh::UID) { 1015 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Mesh); 1016 } else if (classId == SCENE_NS::ClassId::Animation.Id() || classId == META_NS::IAnimation::UID) { 1017 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Animation); 1018 } else if (classId == SCENE_NS::ClassId::Environment.Id() || classId == SCENE_NS::IEnvironment::UID) { 1019 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Environment); 1020 } else { 1021 if (classId != META_NS::IObject::UID && classId != SCENE_NS::ClassId::Node.Id() && 1022 classId != SCENE_NS::INode::UID) { 1023 CORE_LOG_W("%s: uid not known, returning INode instance", __func__); 1024 } 1025 1026 node = GetObjectRegistry().Create<SCENE_NS::INode>(SCENE_NS::ClassId::Node); 1027 } 1028 1029 return node; 1030 } 1031 1032 // Quirk / constraints: 1033 // 1) has name -> cached and asynchronously initialized 1034 // 2) name empty, just an object, not sure if needed at the end 1035 SCENE_NS::INode::Ptr CreateNode(const BASE_NS::string_view name, bool createEngineObject, 1036 const META_NS::ObjectId classId, SCENE_NS::INode::BuildBehavior buildBehavior) override 1037 { 1038 if (const auto& ite = nodes_.find(name); ite != nodes_.cend() && createEngineObject) { 1039 CORE_LOG_W("Refusing to create new duplicate node: %s", BASE_NS::string(name.data(), name.size()).c_str()); 1040 return ite->second; 1041 } 1042 1043 SCENE_NS::INode::Ptr node = CreateNode(classId); 1044 1045 if (node) { 1046 node->BuildChildren(buildBehavior); 1047 BindNodeToEcs(node, name, createEngineObject); 1048 } 1049 return node; 1050 } 1051 1052 SCENE_NS::INode::Ptr CreateResourceFromUri(const META_NS::ObjectId classId, BASE_NS::string_view uri) 1053 { 1054 SCENE_NS::INode::Ptr node; 1055 1056 auto entity = sceneHolder_->GetEntityByUri(uri); 1057 1058 if (CORE_NS::EntityUtil::IsValid(entity)) { 1059 BASE_NS::string name; 1060 if (sceneHolder_->GetEntityName(entity, name)) { 1061 node = CreateNode(classId); 1062 if (node) { 1063 auto ecsScene = GetSelf<SCENE_NS::IEcsScene>(); 1064 auto ecsObject = CreateNewEcsObject({}); 1065 auto nodeInterface = interface_pointer_cast<INodeEcsInterfacePrivate>(node); 1066 nodeInterface->Initialize(ecsScene, ecsObject, {}, "", name, sceneHolder_, entity); 1067 } 1068 } 1069 } 1070 1071 return node; 1072 } 1073 1074 void BindNodeToEcs( 1075 SCENE_NS::INode::Ptr& node, const BASE_NS::string_view fullPath, bool createEngineObject) override 1076 { 1077 SCENE_PLUGIN_VERBOSE_LOG("Scene::BindNodeToEcs called for %s", BASE_NS::string(fullPath).c_str()); 1078 1079 CORE_NS::Entity entity; 1080 auto ecsScene = GetSelf<SCENE_NS::IEcsScene>(); 1081 1082 bool addToRootContainer { false }; 1083 BASE_NS::string nodePath; 1084 BASE_NS::string nodeName; 1085 1086 auto classUid = interface_cast<META_NS::IObject>(node)->GetClassId(); 1087 bool isResourceClassType = (classUid == SCENE_NS::ClassId::Material) || // Material 1088 (classUid == SCENE_NS::ClassId::Mesh) || // Mesh 1089 (classUid == SCENE_NS::ClassId::Animation); // Animation 1090 1091 auto isRealUri = fullPath.find("://") != BASE_NS::string_view::npos; 1092 1093 if (!isRealUri) { 1094 auto cutIx = fullPath.find_last_of('/'); 1095 if (cutIx != BASE_NS::string_view::npos && cutIx < fullPath.size()) { 1096 ++cutIx; 1097 nodePath = BASE_NS::string(fullPath.data(), cutIx); 1098 nodeName = BASE_NS::string(fullPath.data() + cutIx, fullPath.size() - cutIx); 1099 } else if (!fullPath.empty()) { 1100 nodeName = BASE_NS::string(fullPath.data(), fullPath.size()); 1101 } 1102 } 1103 1104 if (nodeName.empty()) { 1105 if (createEngineObject) { 1106 nodeName = interface_cast<META_NS::IObjectInstance>(node)->GetInstanceId().ToString(); 1107 } else { 1108 if (isRealUri) { 1109 auto ecsObject = CreateNewEcsObject({}); 1110 auto nodeInterface = interface_cast<INodeEcsInterfacePrivate>(node); 1111 nodeInterface->Initialize(ecsScene, ecsObject, {}, "", BASE_NS::string(fullPath), sceneHolder_, {}); 1112 } else { 1113 CORE_LOG_W("%s: refusing to create proxy object without valid target, name is empty.", __func__); 1114 } 1115 return; 1116 } 1117 } 1118 1119 auto nodeInterface = interface_cast<INodeEcsInterfacePrivate>(node); 1120 1121 if (nodeInterface->EcsObject() && CORE_NS::EntityUtil::IsValid(nodeInterface->EcsObject()->GetEntity())) { 1122 CORE_LOG_W("%s: refusing to recreate proxy object while current one is valid: %s", __func__, 1123 BASE_NS::string(fullPath).c_str()); 1124 return; 1125 } 1126 1127 auto ecsObject = CreateNewEcsObject({}); 1128 1129 // NEW NODE 1130 if (createEngineObject) { 1131 auto classUid = interface_pointer_cast<META_NS::IObject>(node)->GetClassId(); 1132 auto constructNode = [this, nodePath, nodeName, classUid]( 1133 const auto& sceneHolder) -> CORE_NS::Entity { 1134 CORE_NS::Entity entity; 1135 if (sceneHolder) { 1136 // Should not need to type this deep here 1137 if (classUid == SCENE_NS::ClassId::Material) { 1138 entity = sceneHolder->CreateMaterial(nodeName); 1139 } else if (classUid == SCENE_NS::ClassId::Camera) { 1140 entity = sceneHolder->CreateCamera(nodePath, nodeName, 0); 1141 } else if (auto node = sceneHolder->CreateNode(nodePath, nodeName)) { 1142 entity = node->GetEntity(); 1143 1144 sceneHolder->EnableLayerComponent(entity); 1145 if (classUid == SCENE_NS::ClassId::Light) { 1146 sceneHolder->EnableLightComponent(entity); 1147 } 1148 if (classUid == SCENE_NS::ClassId::Environment) { 1149 sceneHolder->EnableEnvironmentComponent(entity); 1150 } 1151 } 1152 } 1153 1154 return entity; 1155 }; 1156 if (GetValue(Asynchronous())) { 1157 AddEngineTask(MakeTask( 1158 [constructNode](const auto& sceneHolder) { 1159 constructNode(sceneHolder); 1160 return false; 1161 }, 1162 sceneHolder_), 1163 false); 1164 } else { 1165 entity = constructNode(sceneHolder_); 1166 } 1167 1168 addToRootContainer = true; 1169 // If we don't have parent .. then attach to root. 1170 if (nodePath.empty() && !isResourceClassType) { 1171 nodePath = "/" + rootNodeId_ + "/"; 1172 } 1173 1174 if (META_NS::Property<uint32_t> creationPolicy = nodeInterface->GetLifecycleInfo()) { 1175 creationPolicy->SetValue(NODE_LC_CREATED); 1176 nodeInterface->ClaimOwnershipOfEntity(true); 1177 } 1178 } else { 1179 // We expect to find the node from ecs (sooner or later) 1180 // If we are running synchronously, we could check it and even 1181 // tell the calling code if the node is there. 1182 1183 // We'd need to know some additional info about the node parent etc 1184 if (META_NS::Property<uint32_t> creationPolicy = nodeInterface->GetLifecycleInfo()) { 1185 creationPolicy->SetValue(NODE_LC_MIRROR_EXISTING); 1186 } 1187 } 1188 1189 SCENE_NS::INode::Ptr parent; 1190 1191 if (!isResourceClassType) { 1192 auto containable = interface_cast<META_NS::IContainable>(node); 1193 if (containable->GetParent()) { 1194 parent = interface_pointer_cast<SCENE_NS::INode>(containable->GetParent()); 1195 } 1196 1197 if (!parent) { 1198 parent = addToRootContainer ? RootNode()->GetValue() : currentParent_; 1199 } 1200 } 1201 1202 nodeInterface->Initialize(ecsScene, ecsObject, parent, nodePath, nodeName, sceneHolder_, entity); 1203 } 1204 1205 void UpdateCachedNodePath(const SCENE_NS::INode::Ptr& node) override 1206 { 1207 if (node) { 1208 if (interface_cast<META_NS::IObject>(node)->GetClassId() != SCENE_NS::ClassId::Node) { 1209 UpdateCachedReference(node); 1210 return; 1211 } 1212 1213 bool found = false; 1214 1215 for (auto&& ite : nodes_) { 1216 if (ite.second == node) { 1217 nodes_.erase(ite.first); 1218 break; 1219 } 1220 } 1221 1222 BASE_NS::string pathString = node->Path()->GetValue(); 1223 pathString.append(node->Name()->GetValue()); 1224 nodes_[pathString] = node; 1225 } 1226 } 1227 1228 void SetCacheEnabled(const SCENE_NS::INode::Ptr& node, bool enabled) override 1229 { 1230 if (!node) { 1231 return; 1232 } 1233 1234 if (enabled) { 1235 BASE_NS::string pathString = node->Path()->GetValue(); 1236 pathString.append(node->Name()->GetValue()); 1237 nodes_[pathString] = node; 1238 } else { 1239 for (auto&& ite : nodes_) { 1240 if (ite.second == node) { 1241 nodes_.erase(ite.first); 1242 break; 1243 } 1244 } 1245 } 1246 } 1247 1248 typedef BASE_NS::shared_ptr<CORE_NS::IInterface> (*fun)(SceneImpl* me, const BASE_NS::string_view); 1249 1250 static BASE_NS::shared_ptr<CORE_NS::IInterface> relmat(SceneImpl* me, const BASE_NS::string_view p) 1251 { 1252 return me->ReleaseMaterial(p); 1253 } 1254 static BASE_NS::shared_ptr<CORE_NS::IInterface> relmesh(SceneImpl* me, const BASE_NS::string_view p) 1255 { 1256 return me->ReleaseMesh(p); 1257 } 1258 static BASE_NS::shared_ptr<CORE_NS::IInterface> relanim(SceneImpl* me, const BASE_NS::string_view p) 1259 { 1260 return me->ReleaseAnimation(p); 1261 } 1262 static BASE_NS::shared_ptr<CORE_NS::IInterface> relnode(SceneImpl* me, const BASE_NS::string_view p) 1263 { 1264 return me->ReleaseNode(p); 1265 } 1266 template<typename Type> 1267 bool CacheNode(const char* const tname, const SCENE_NS::INode::Ptr& node, 1268 BASE_NS::unordered_map<BASE_NS::string, typename Type::WeakPtr>& cache, fun func) 1269 { 1270 if (auto typed = interface_pointer_cast<Type>(node)) { 1271 BASE_NS::string uri; 1272 bool found = false; 1273 1274 if (node->GetInterface(SCENE_NS::ICamera::UID)) { 1275 // handle camera naming.. 1276 uri = node->Path()->GetValue(); 1277 uri.append(node->Name()->GetValue()); 1278 1279 } else { 1280 auto ecsObject = interface_pointer_cast<SCENE_NS::IEcsObject>(typed); 1281 uri = sceneHolder_->GetResourceId(ecsObject->GetEntity()); 1282 if (uri.empty()) { 1283 uri = node->Name()->GetValue() + ":" + BASE_NS::to_hex(ecsObject->GetEntity().id); 1284 } 1285 } 1286 1287 for (auto&& ite : cache) { 1288 if (ite.second.lock() == typed) { 1289 if (uri != ite.first) { 1290 cache[uri] = interface_pointer_cast<Type>(func(this, ite.first)); 1291 SCENE_PLUGIN_VERBOSE_LOG("Updating cached reference of %s: %s", tname, uri.c_str()); 1292 } 1293 found = true; 1294 break; // reference is valid so return true regardless if the node was moved 1295 } 1296 } 1297 1298 if (!found) { 1299 SCENE_PLUGIN_VERBOSE_LOG("Caching reference of %s: %s", tname, uri.c_str()); 1300 cache[uri] = typed; 1301 } 1302 return true; 1303 } 1304 return false; 1305 } 1306 void UpdateCachedReference(const SCENE_NS::INode::Ptr& node) override 1307 { 1308 if (node) { 1309 if (CacheNode<SCENE_NS::IMaterial>("material", node, materials_, relmat) || 1310 CacheNode<SCENE_NS::IMesh>("mesh", node, meshes_, relmesh) || 1311 CacheNode<META_NS::IAnimation>("animation", node, animations_, relanim)) { 1312 // completed. (meshes, materials and animations are not added to node list) 1313 return; 1314 } 1315 if (CacheNode<SCENE_NS::ICamera>("camera", node, cameras_, relnode)) { 1316 // camera cache updated. 1317 auto* obj = interface_cast<SCENE_NS::IEcsObject>(node); 1318 if (obj) { 1319 auto entity = obj->GetEntity(); 1320 if (CORE_NS::EntityUtil::IsValid(entity)) { 1321 sceneHolder_->AddCamera(entity); 1322 } else { 1323 CORE_LOG_V("camera has no entity id yet"); 1324 } 1325 } else { 1326 CORE_LOG_V("camera has no IEcsObject"); 1327 } 1328 } 1329 // update node cache. 1330 1331 bool found = false; 1332 BASE_NS::string uri = node->Path()->GetValue(); 1333 uri.append(node->Name()->GetValue()); 1334 1335 for (auto&& ite : nodes_) { 1336 if (ite.second == node) { 1337 if (uri != ite.first) { 1338 nodes_[uri] = ReleaseNode(ite.first); 1339 } 1340 found = true; 1341 break; // reference is valid so return true regardless if the node was moved 1342 } 1343 } 1344 1345 if (!found) { 1346 nodes_[uri] = node; 1347 } 1348 } 1349 } 1350 1351 // Release Node Reference from cache 1352 SCENE_NS::INode::Ptr ReleaseNode(const BASE_NS::string_view name) override 1353 { 1354 SCENE_NS::INode::Ptr ret {}; 1355 if (auto ite = nodes_.extract(BASE_NS::string(name)); !ite.empty()) { 1356 ret = BASE_NS::move(ite.mapped()); 1357 if (auto privateIntf = interface_cast<INodeEcsInterfacePrivate>(ret)) { 1358 privateIntf->ClaimOwnershipOfEntity(true); 1359 } 1360 RemoveNodeFromCurrentContainer(ret); 1361 if (auto cam = interface_pointer_cast<SCENE_NS::ICamera>(ret)) { 1362 ReleaseCamera(name); 1363 } 1364 } 1365 return ret; 1366 } 1367 void ReleaseNode(const SCENE_NS::INode::Ptr& node) override 1368 { 1369 if (node) { 1370 ReleaseNode(node->Path()->GetValue() + node->Name()->GetValue()); 1371 } 1372 } 1373 1374 SCENE_NS::IMaterial::Ptr ReleaseMaterial(const BASE_NS::string_view name) override 1375 { 1376 SCENE_NS::IMaterial::Ptr ret {}; 1377 if (auto ite = materials_.find(name); ite != materials_.end()) { 1378 ret = ite->second.lock(); 1379 materials_.erase(ite); 1380 } 1381 return ret; 1382 } 1383 1384 SCENE_NS::IMesh::Ptr ReleaseMesh(const BASE_NS::string_view name) override 1385 { 1386 SCENE_NS::IMesh::Ptr ret {}; 1387 if (auto ite = meshes_.find(name); ite != meshes_.end()) { 1388 ret = ite->second.lock(); 1389 meshes_.erase(ite); 1390 } 1391 1392 return ret; 1393 } 1394 1395 META_NS::IAnimation::Ptr ReleaseAnimation(const BASE_NS::string_view name) override 1396 { 1397 META_NS::IAnimation::Ptr ret {}; 1398 if (auto ite = animations_.find(name); ite != animations_.end()) { 1399 ret = ite->second.lock(); 1400 animations_.erase(ite); 1401 } 1402 return ret; 1403 } 1404 1405 SCENE_NS::ICamera::Ptr ReleaseCamera(const BASE_NS::string_view name) 1406 { 1407 SCENE_NS::ICamera::Ptr ret {}; 1408 if (auto ite = cameras_.find(name); ite != cameras_.end()) { 1409 ret = ite->second.lock(); 1410 // make sure the rendertarget/bitmap is also released. 1411 SetBitmap(nullptr, ret); 1412 cameras_.erase(ite); 1413 } 1414 return ret; 1415 } 1416 1417 SCENE_NS::IMesh::Ptr CreateMeshFromArraysI16( 1418 const BASE_NS::string_view name, SCENE_NS::MeshGeometryArrayPtr<uint16_t> arrays) override 1419 { 1420 return CreateMeshFromArrays<uint16_t>(name, arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT16); 1421 } 1422 1423 SCENE_NS::IMesh::Ptr CreateMeshFromArraysI32( 1424 const BASE_NS::string_view name, SCENE_NS::MeshGeometryArrayPtr<uint32_t> arrays) override 1425 { 1426 return CreateMeshFromArrays<uint32_t>(name, arrays, RENDER_NS::IndexType::CORE_INDEX_TYPE_UINT32); 1427 } 1428 1429 template<typename IndicesType> 1430 SCENE_NS::IMesh::Ptr CreateMeshFromArrays(const BASE_NS::string_view name, 1431 SCENE_NS::MeshGeometryArrayPtr<IndicesType> arrays, RENDER_NS::IndexType indexType) 1432 { 1433 auto nameString = BASE_NS::shared_ptr(new BASE_NS::string(name.data(), name.size())); 1434 1435 AddEngineTask(MakeTask( 1436 [arrays, nameString, indexType](auto sceneHolder) { 1437 auto meshEntity = sceneHolder->template CreateMeshFromArrays<IndicesType>( 1438 *nameString, arrays, indexType); 1439 if (!sceneHolder->IsAsync()) { 1440 *nameString = sceneHolder->GetResourceId(meshEntity); 1441 } 1442 1443 return false; 1444 }, 1445 sceneHolder_), 1446 false); 1447 return GetMesh(*nameString); 1448 } 1449 1450 void InstantiateMaterialProxies() override 1451 { 1452 AddEngineTask(MakeTask( 1453 [me = BASE_NS::weak_ptr(GetSelf<SCENE_NS::IScene>())](auto sceneHolder) { 1454 auto ids = sceneHolder->ListMaterialNames(); 1455 sceneHolder->QueueApplicationTask(MakeTask( 1456 [ids](auto self) { 1457 for (auto& id : *ids) { 1458 self->GetMaterial(id); 1459 } 1460 return false; 1461 }, 1462 me), 1463 false); 1464 return false; 1465 }, 1466 sceneHolder_), 1467 false); 1468 } 1469 1470 void InstantiateMeshProxies() override 1471 { 1472 AddEngineTask(MakeTask( 1473 [me = BASE_NS::weak_ptr(GetSelf<SCENE_NS::IScene>())](auto sceneHolder) { 1474 auto ids = sceneHolder->ListMeshNames(); 1475 sceneHolder->QueueApplicationTask(MakeTask( 1476 [ids](auto self) { 1477 for (auto& id : *ids) { 1478 self->GetMesh(id); 1479 } 1480 1481 return false; 1482 }, 1483 me), 1484 false); 1485 1486 return false; 1487 }, 1488 sceneHolder_), 1489 false); 1490 } 1491 1492public: 1493 ~SceneImpl() override 1494 { 1495 allAnims_.clear(); 1496 if (sceneHolder_) { 1497 DetachScene(); 1498 } 1499 1500 cameraNodePtr_.reset(); 1501 rootNodePtr_.reset(); 1502 1503 UnsubscribeFromPropertyChanges(); 1504 1505 if (sceneHolder_) { 1506 sceneHolder_->Uninitialize(); 1507 sceneHolder_.reset(); 1508 } 1509 } 1510 1511 void SetEcsInitializationCallback(IPrepareSceneForInitialization::WeakPtr callback) override 1512 { 1513 if (sceneHolder_) { 1514 sceneHolder_->SetEcsInitializationCallback(callback); 1515 } else { 1516 CORE_LOG_W("%s: sceneholder does not exist, cannot set callback", __func__); 1517 } 1518 } 1519 1520 SCENE_NS::IPickingResult::Ptr GetWorldAABB(const BASE_NS::Math::Mat4X4& world, const BASE_NS::Math::Vec3& aabbMin, 1521 const BASE_NS::Math::Vec3& aabbMax) override 1522 { 1523 auto ret = META_NS::GetObjectRegistry().Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request); 1524 if (ret) { 1525 AddEngineTask( 1526 META_NS::MakeCallback<META_NS::ITaskQueueTask>([w = world, min = aabbMin, max = aabbMax, 1527 weakRet = BASE_NS::weak_ptr(ret), 1528 weakSh = BASE_NS::weak_ptr(sceneHolder_)]() { 1529 if (auto sh = weakSh.lock()) { 1530 if (auto ret = weakRet.lock()) { 1531 if (sh->GetWorldAABB(ret, w, min, max)) { 1532 sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() { 1533 if (auto writable = 1534 interface_pointer_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>( 1535 weakRet)) { 1536 writable->MarkReady(); 1537 } 1538 return false; 1539 }), 1540 false); 1541 } 1542 } 1543 } 1544 return false; 1545 }), 1546 false); 1547 return ret; 1548 } 1549 return SCENE_NS::IPickingResult::Ptr(); 1550 } 1551 1552 SCENE_NS::IRayCastResult::Ptr RayCast( 1553 const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction) override 1554 { 1555 auto ret = 1556 META_NS::GetObjectRegistry().Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest); 1557 if (ret) { 1558 AddEngineTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([origin = start, dir = direction, 1559 weakRet = BASE_NS::weak_ptr(ret), 1560 weakSh = BASE_NS::weak_ptr(sceneHolder_), 1561 weakSelf = BASE_NS::weak_ptr( 1562 GetSelf<SCENE_NS::IScene>())]() { 1563 if (auto sh = weakSh.lock()) { 1564 if (auto ret = weakRet.lock()) { 1565 if (sh->RayCast(ret, origin, dir)) { 1566 sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, 1567 weakSelf]() { 1568 if (auto writable = 1569 interface_pointer_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>( 1570 weakRet)) { 1571 if (auto self = weakSelf.lock()) { 1572 // resolve proxy nodes 1573 for (size_t ii = writable->MetaData().size(); ii > 0;) { 1574 --ii; 1575 writable->MutableData().at(ii).node = 1576 self->GetNode(writable->MetaData().at(ii)); 1577 } 1578 writable->MarkReady(); 1579 } 1580 } 1581 return false; 1582 }), 1583 false); 1584 } 1585 } 1586 } 1587 return false; 1588 }), 1589 false); 1590 return ret; 1591 } 1592 return SCENE_NS::IRayCastResult::Ptr(); 1593 } 1594 1595 SCENE_NS::IRayCastResult::Ptr RayCast( 1596 const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction, uint64_t layerMask) override 1597 { 1598 auto ret = 1599 META_NS::GetObjectRegistry().Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest); 1600 if (ret) { 1601 AddEngineTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([origin = start, dir = direction, layerMask, 1602 weakRet = BASE_NS::weak_ptr(ret), 1603 weakSh = BASE_NS::weak_ptr(sceneHolder_), 1604 weakSelf = BASE_NS::weak_ptr( 1605 GetSelf<SCENE_NS::IScene>())]() { 1606 if (auto sh = weakSh.lock()) { 1607 if (auto ret = weakRet.lock()) { 1608 if (sh->RayCast(ret, origin, dir, layerMask)) { 1609 sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, 1610 weakSelf]() { 1611 if (auto writable = 1612 interface_pointer_cast<SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>( 1613 weakRet)) { 1614 if (auto self = weakSelf.lock()) { 1615 // resolve proxy nodes 1616 for (size_t ii = writable->MetaData().size(); ii > 0;) { 1617 --ii; 1618 writable->MutableData().at(ii).node = 1619 self->GetNode(writable->MetaData().at(ii)); 1620 } 1621 writable->MarkReady(); 1622 } 1623 } 1624 return false; 1625 }), 1626 false); 1627 } 1628 } 1629 } 1630 return false; 1631 }), 1632 false); 1633 return ret; 1634 } 1635 return SCENE_NS::IRayCastResult::Ptr(); 1636 } 1637 BASE_NS::vector<CORE_NS::Entity> RenderCameras() override 1638 { 1639 if (sceneHolder_) { 1640 return sceneHolder_->RenderCameras(); 1641 } 1642 return {}; 1643 } 1644 void ActivateCamera(const SCENE_NS::ICamera::Ptr& camera) override 1645 { 1646 if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 1647 auto ent = e->GetEntity(); 1648 sceneHolder_->ActivateCamera(ent); 1649 } 1650 } 1651 1652 void DeactivateCamera(const SCENE_NS::ICamera::Ptr& camera) override 1653 { 1654 if (!camera) { 1655 return; 1656 } 1657 1658 if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 1659 sceneHolder_->DeactivateCamera(e->GetEntity()); 1660 } 1661 } 1662 bool IsCameraActive(const SCENE_NS::ICamera::Ptr& camera) override 1663 { 1664 if (!camera) { 1665 return false; 1666 } 1667 1668 if (auto e = interface_pointer_cast<SCENE_NS::IEcsObject>(camera)) { 1669 return sceneHolder_->IsCameraActive(e->GetEntity()); 1670 } 1671 return false; 1672 } 1673 1674private: 1675 void SubscribeToPropertyChanges() 1676 { 1677 if (RootNode()) { 1678 rootNodeChangedToken_ = RootNode()->OnChanged()->AddHandler( 1679 META_NS::MakeCallback<META_NS::IOnChanged>(this, &SceneImpl::OnRootNodeChanged)); 1680 } 1681 1682 if (Uri()) { 1683 uriHandlerToken_ = Uri()->OnChanged()->AddHandler( 1684 META_NS::MakeCallback<META_NS::IOnChanged>([this]() { this->Load(Uri()->GetValue()); })); 1685 } 1686 1687 // Start listening changes of the scene controller properties. These may go to different place some day 1688 if (SystemGraphUri()) { 1689 systemGraphUriHandlerToken_ = SystemGraphUri()->OnChanged()->AddHandler( 1690 META_NS::MakeCallback<META_NS::IOnChanged>(this, &SceneImpl::onSystemGraphUriChanged)); 1691 } 1692 } 1693 1694 void UnsubscribeFromPropertyChanges() 1695 { 1696 if (Uri()) { 1697 Uri()->OnChanged()->RemoveHandler(uriHandlerToken_); 1698 uriHandlerToken_ = {}; 1699 } 1700 1701 if (RootNode()) { 1702 RootNode()->OnChanged()->RemoveHandler(rootNodeChangedToken_); 1703 rootNodeChangedToken_ = {}; 1704 } 1705 1706 if (SystemGraphUri()) { 1707 SystemGraphUri()->OnChanged()->RemoveHandler(systemGraphUriHandlerToken_); 1708 systemGraphUriHandlerToken_ = {}; 1709 } 1710 1711 if (Asynchronous()) { 1712 Asynchronous()->OnChanged()->RemoveHandler(asyncChangedToken_); 1713 asyncChangedToken_ = {}; 1714 } 1715 } 1716 1717 void OnRootNodeChanged() 1718 { 1719 auto contentObject = interface_pointer_cast<META_NS::IObject>(RootNode()->GetValue()); 1720 contentImpl_->SetContent(contentObject); 1721 1722 META_NS::HierarchyChangeModeValue changeMode; 1723 changeMode.Set(META_NS::HierarchyChangeMode::NOTIFY_CONTAINER); 1724 hierarchyController_->SetTarget(contentObject, changeMode); 1725 } 1726 1727 META_NS::IEvent::Token systemGraphUriHandlerToken_ {}; 1728 META_NS::IEvent::Token renderSizeHandlerToken_ {}; 1729 META_NS::IEvent::Token cameraHandlerToken_ {}; 1730 META_NS::IEvent::Token uriHandlerToken_ {}; 1731 META_NS::IEvent::Token rootNodeChangedToken_ {}; 1732 META_NS::IEvent::Token renderModeChangedToken_ {}; 1733 META_NS::IEvent::Token asyncChangedToken_ {}; 1734 1735 SceneHolder::Ptr sceneHolder_; 1736 1737 BASE_NS::string rootNodeId_; 1738 BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::INode::Ptr> nodes_; 1739 BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::ICamera::WeakPtr> cameras_; 1740 BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMesh::WeakPtr> meshes_; 1741 BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMaterial::WeakPtr> materials_; 1742 BASE_NS::unordered_map<BASE_NS::string, META_NS::IAnimation::WeakPtr> animations_; 1743 1744 BASE_NS::unordered_map<BASE_NS::string, SCENE_NS::IMaterial::WeakPtr> uriMaterials_; 1745 1746 uint64_t instanceNumber_ { 0 }; 1747 1748 // Preserve property instances while scene / ecs is invalid 1749 SCENE_NS::INode::Ptr rootNodePtr_ {}; 1750 SCENE_NS::ICamera::Ptr cameraNodePtr_ {}; 1751 META_NS::IContent::Ptr contentImpl_ {}; 1752 1753 uint64_t defaultCameraHandle_ { 0 }; 1754 1755 // We need to add a node onto a container in bit awkward position (without exposing it to a public api) 1756 // Store it here. 1757 SCENE_NS::INode::Ptr currentParent_ {}; 1758 META_NS::IObjectHierarchyObserver::Ptr hierarchyController_; 1759 1760 META_NS::IAnimationController::Ptr animationController_; 1761}; 1762 1763BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> SceneImpl::GetAnimations() const 1764{ 1765 return animationController_->GetAnimations(); 1766} 1767BASE_NS::vector<BASE_NS::weak_ptr<META_NS::IAnimation>> SceneImpl::GetRunning() const 1768{ 1769 return animationController_->GetRunning(); 1770} 1771bool SceneImpl::AddAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) 1772{ 1773 return animationController_->AddAnimation(animation); 1774} 1775bool SceneImpl::RemoveAnimation(const BASE_NS::shared_ptr<META_NS::IAnimation>& animation) 1776{ 1777 return animationController_->RemoveAnimation(animation); 1778} 1779void SceneImpl::Clear() 1780{ 1781 animationController_->Clear(); 1782} 1783META_NS::IAnimationController::StepInfo SceneImpl::Step(const META_NS::IClock::ConstPtr& clock) 1784{ 1785 return animationController_->Step(clock); 1786} 1787 1788} // namespace 1789SCENE_BEGIN_NAMESPACE() 1790void RegisterSceneImpl() 1791{ 1792 META_NS::GetObjectRegistry().RegisterObjectType<SceneImpl>(); 1793} 1794void UnregisterSceneImpl() 1795{ 1796 META_NS::GetObjectRegistry().UnregisterObjectType<SceneImpl>(); 1797} 1798SCENE_END_NAMESPACE() 1799