1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "scene_manager.h"
17
18 #include <scene/ext/intf_ecs_context.h>
19 #include <scene/ext/intf_internal_scene.h>
20 #include <scene/ext/util.h>
21 #include <scene/interface/intf_application_context.h>
22 #include <scene/interface/intf_environment.h>
23 #include <scene/interface/intf_image.h>
24 #include <scene/interface/intf_material.h>
25 #include <scene/interface/intf_postprocess.h>
26 #include <scene/interface/intf_scene.h>
27 #include <scene/interface/intf_scene_manager.h>
28 #include <scene/interface/intf_shader.h>
29 #include <scene/interface/resource/types.h>
30
31 #include <core/intf_engine.h>
32 #include <render/intf_render_context.h>
33
34 #include <meta/api/task_queue.h>
35 #include <meta/interface/builtin_objects.h>
36 #include <meta/interface/intf_object_hierarchy_observer.h>
37 #include <meta/interface/resource/intf_object_resource.h>
38
39 #include "asset/asset_object.h"
40 #include "resource/resource_types.h"
41
SCENE_BEGIN_NAMESPACE()42 SCENE_BEGIN_NAMESPACE()
43
44 bool SceneManager::Build(const META_NS::IMetadata::Ptr& d)
45 {
46 bool res = Super::Build(d);
47 if (res) {
48 if (d) {
49 context_ = GetInterfaceBuildArg<IRenderContext>(d, "RenderContext");
50 opts_ = GetBuildArg<SceneOptions>(d, "Options");
51 }
52 if (!context_) {
53 if (auto app = GetDefaultApplicationContext()) {
54 CORE_LOG_D("Using default context for scene manager");
55 context_ = GetDefaultApplicationContext()->GetRenderContext();
56 if (!context_) {
57 CORE_LOG_W("No default context set");
58 return false;
59 }
60 // use opts from app context if we are using it
61 opts_ = app->GetDefaultSceneOptions();
62 }
63 }
64 RegisterResourceTypes(context_, opts_);
65 }
66 return res;
67 }
68
CreateContext(SceneOptions opts) const69 META_NS::IMetadata::Ptr SceneManager::CreateContext(SceneOptions opts) const
70 {
71 auto context = CreateRenderContextArg(context_);
72 if (context) {
73 if (auto op = META_NS::ConstructProperty<SceneOptions>("Options", opts)) {
74 context->AddProperty(op);
75 }
76 }
77 return context;
78 }
79
CreateScene()80 Future<IScene::Ptr> SceneManager::CreateScene()
81 {
82 return CreateScene(opts_);
83 }
84
CreateScene(SceneOptions opts)85 Future<IScene::Ptr> SceneManager::CreateScene(SceneOptions opts)
86 {
87 return context_->AddTask([context = CreateContext(BASE_NS::move(opts))] {
88 if (auto scene = META_NS::GetObjectRegistry().Create<IScene>(SCENE_NS::ClassId::Scene, context)) {
89 auto& ecs = scene->GetInternalScene()->GetEcsContext();
90 if (ecs.CreateUnnamedRootNode()) {
91 return scene;
92 }
93 CORE_LOG_E("Failed to create root node");
94 }
95 return SCENE_NS::IScene::Ptr {};
96 });
97 }
98
Load(const IScene::Ptr & scene,BASE_NS::string_view uri)99 static IScene::Ptr Load(const IScene::Ptr& scene, BASE_NS::string_view uri)
100 {
101 CORE_LOG_I("Loading scene: '%s'", BASE_NS::string(uri).c_str());
102 if (auto assets = META_NS::GetObjectRegistry().Create<IAssetObject>(ClassId::AssetObject)) {
103 if (assets->Load(scene, uri)) {
104 if (auto att = interface_cast<META_NS::IAttach>(scene)) {
105 att->Attach(assets);
106 }
107 return scene;
108 }
109 }
110 return {};
111 }
112
CreateScene(BASE_NS::string_view uri)113 Future<IScene::Ptr> SceneManager::CreateScene(BASE_NS::string_view uri)
114 {
115 return CreateScene(uri, opts_);
116 }
117
CreateScene(BASE_NS::string_view uri,SceneOptions opts)118 Future<IScene::Ptr> SceneManager::CreateScene(BASE_NS::string_view uri, SceneOptions opts)
119 {
120 if (uri == "" || uri == "scene://empty") {
121 return CreateScene(BASE_NS::move(opts));
122 }
123 if (!context_) {
124 return {};
125 }
126 return context_->AddTask(
127 [path = BASE_NS::string(uri), renderContext = context_, args = CreateContext(BASE_NS::move(opts))] {
128 IScene::Ptr result;
129 if (path.ends_with(".scene") || path.ends_with(".scene2")) {
130 // Try loading as an editor project
131 if (SetProjectPath(renderContext, path, ProjectPathAction::REGISTER)) {
132 // Rely on an implementation detail: If the path is already registered, it can be re-registered.
133 // Unregistering will remove only the re-registered path and leave the original.
134 result = LoadSceneWithIndex(renderContext, path);
135 SetProjectPath(renderContext, path, ProjectPathAction::UNREGISTER);
136 }
137 }
138 if (!result) {
139 // Was not an editor project (so could be either a .gltf or old format .scene)
140 result = META_NS::GetObjectRegistry().Create<IScene>(SCENE_NS::ClassId::Scene, args);
141 Load(result, path);
142 }
143 return result;
144 });
145 }
146
LoadDefaultResourcesIfNeeded(const CORE_NS::IResourceManager::Ptr & resources)147 void SceneManager::LoadDefaultResourcesIfNeeded(const CORE_NS::IResourceManager::Ptr& resources)
148 {
149 static constexpr auto DEFAULT_PROJECT_RESOURCE_GROUP_URI = "project://default_resources.res";
150 bool foundDefault = false;
151 for (auto&& group : resources->GetResourceGroups()) {
152 // The project default resource group has no name
153 if (group.empty()) {
154 foundDefault = true;
155 break;
156 }
157 }
158 if (!foundDefault) {
159 // Did not find unnamed (default) resource group, load default resource file
160 resources->Import(DEFAULT_PROJECT_RESOURCE_GROUP_URI);
161 }
162 }
163
LoadSceneWithIndex(const IRenderContext::Ptr & context,BASE_NS::string_view uri)164 IScene::Ptr SceneManager::LoadSceneWithIndex(const IRenderContext::Ptr& context, BASE_NS::string_view uri)
165 {
166 if (!context) {
167 return {};
168 }
169 auto resources = context->GetResources();
170 if (!resources) {
171 return {};
172 }
173
174 // Make sure that project default resource group has been loaded
175 LoadDefaultResourcesIfNeeded(resources);
176
177 const auto index = GuessIndexFilePath(uri);
178 auto ires = resources->Import(index);
179 if (ires != CORE_NS::IResourceManager::Result::OK) {
180 CORE_LOG_E("Failed to load resource index: %s [%d]", index.c_str(), int(ires));
181 return {};
182 }
183 CORE_NS::ResourceId rid { BASE_NS::string(uri) };
184 // see if the scene is resource in the index, if not, add it
185 if (!resources->GetResourceInfo(rid).id.IsValid()) {
186 resources->AddResource(rid, ClassId::SceneResource.Id().ToUid(), uri);
187 }
188 return interface_pointer_cast<IScene>(resources->GetResource(rid));
189 }
190
SetProjectPath(const IRenderContext::Ptr & renderContext,BASE_NS::string_view uri,ProjectPathAction action)191 bool SceneManager::SetProjectPath(
192 const IRenderContext::Ptr& renderContext, BASE_NS::string_view uri, ProjectPathAction action)
193 {
194 if (renderContext) {
195 if (const auto renderer = renderContext->GetRenderer()) {
196 auto& fileManager = renderer->GetEngine().GetFileManager();
197 const auto pathToProject = GuessProjectPath(uri);
198 if (action == ProjectPathAction::REGISTER) {
199 return fileManager.RegisterPath("project", pathToProject, true);
200 } else {
201 fileManager.UnregisterPath("project", pathToProject);
202 }
203 return true;
204 }
205 }
206 CORE_LOG_E("Unable to access file manager: render context missing");
207 return false;
208 }
209
GuessIndexFilePath(BASE_NS::string_view uri)210 BASE_NS::string SceneManager::GuessIndexFilePath(BASE_NS::string_view uri)
211 {
212 auto pos = uri.find_last_of('.');
213 return uri.substr(0, pos) + ".res";
214 }
215
GuessProjectPath(BASE_NS::string_view uri)216 BASE_NS::string SceneManager::GuessProjectPath(BASE_NS::string_view uri)
217 {
218 const auto secondToLastSlashPos = uri.find_last_of('/', uri.find_last_of('/') - 1);
219 return BASE_NS::string { uri.substr(0, secondToLastSlashPos) };
220 }
221
222 SCENE_END_NAMESPACE()
223