• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "node.h"
17 
18 #include <scene/ext/intf_ecs_context.h>
19 #include <scene/ext/util.h>
20 #include <scene/interface/intf_application_context.h>
21 #include <scene/interface/intf_scene_manager.h>
22 
23 #include <meta/api/object_name.h>
24 #include <meta/base/interface_utils.h>
25 
26 #include "core/ecs.h"
27 
SCENE_BEGIN_NAMESPACE()28 SCENE_BEGIN_NAMESPACE()
29 
30 bool Node::Build(const META_NS::IMetadata::Ptr& d)
31 {
32     return Super::Build(d);
33 }
34 
Destroy()35 void Node::Destroy()
36 {
37     if (startableHandler_) {
38         startableHandler_->StopAll(GetAttachmentContainer(false));
39         startableHandler_.reset();
40     }
41     if (!imported_.empty()) {
42         if (auto s = GetInternalScene()) {
43             auto& ecs = s->GetEcsContext();
44             for (auto&& ent : imported_) {
45                 if (!ecs.IsNodeEntity(ent)) { // Nodes are handled by the hierarchy so don't delete those here?
46                     ecs.RemoveEntity(ent);
47                 }
48             }
49         }
50     }
51     Super::Destroy();
52 }
53 
GetScene() const54 IScene::Ptr Node::GetScene() const
55 {
56     if (auto s = GetInternalScene()) {
57         return s->GetScene();
58     }
59     return nullptr;
60 }
61 
GetParent(NodeTag) const62 Future<INode::Ptr> Node::GetParent(NodeTag) const
63 {
64     if (auto s = GetInternalScene()) {
65         return s->AddTask([=] {
66             auto ent = s->GetEcsContext().GetParent(GetEntity());
67             return CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
68         });
69     }
70     return {};
71 }
72 
SetEcsObject(const IEcsObject::Ptr & obj)73 bool Node::SetEcsObject(const IEcsObject::Ptr& obj)
74 {
75     if (Super::SetEcsObject(obj)) {
76         if (auto scene = GetInternalScene()) {
77             if (scene->GetOptions().enableStartables) {
78                 if (!startableHandler_) {
79                     startableHandler_ = BASE_NS::make_unique<StartableHandler>(GetSelf<INode>());
80                 }
81                 if (startableHandler_) {
82                     startableHandler_->StartAll(StartableHandler::StartType::DEFERRED);
83                 }
84             }
85         }
86         return true;
87     }
88     return false;
89 }
90 
Attach(const IObject::Ptr & attachment,const IObject::Ptr & dataContext)91 bool Node::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
92 {
93     if (Super::Attach(attachment, dataContext)) {
94         if (startableHandler_) {
95             startableHandler_->Start(attachment, StartableHandler::StartType::DEFERRED);
96         }
97         return true;
98     }
99     return false;
100 }
Detach(const IObject::Ptr & attachment)101 bool Node::Detach(const IObject::Ptr& attachment)
102 {
103     if (startableHandler_) {
104         startableHandler_->Stop(attachment);
105     }
106     return Super::Detach(attachment);
107 }
108 
GetChildren() const109 Future<BASE_NS::vector<INode::Ptr>> Node::GetChildren() const
110 {
111     if (auto s = GetInternalScene()) {
112         return s->AddTask([=] { return s->GetChildren(object_); });
113     }
114     return {};
115 }
116 
RemoveChild(const INode::Ptr & child)117 Future<bool> Node::RemoveChild(const INode::Ptr& child)
118 {
119     if (auto s = GetInternalScene()) {
120         if (auto ecsobj = interface_pointer_cast<IEcsObjectAccess>(child)) {
121             return s->AddTask([=] { return s->RemoveChild(object_, ecsobj->GetEcsObject()); });
122         }
123     }
124     return {};
125 }
AddChild(const INode::Ptr & child,size_t index)126 Future<bool> Node::AddChild(const INode::Ptr& child, size_t index)
127 {
128     if (auto s = GetInternalScene()) {
129         return s->AddTask([=] { return s->AddChild(object_, child, index); });
130     }
131     return {};
132 }
GetName() const133 BASE_NS::string Node::GetName() const
134 {
135     return NamedSceneObject::GetName();
136 }
GetPath() const137 Future<BASE_NS::string> Node::GetPath() const
138 {
139     if (auto s = GetInternalScene()) {
140         return s->AddTask([=] { return object_->GetPath(); });
141     }
142     return {};
143 }
144 
ImportChild(const INode::ConstPtr & node)145 Future<INode::Ptr> Node::ImportChild(const INode::ConstPtr& node)
146 {
147     if (!node) {
148         return {};
149     }
150     if (node->GetScene() == GetScene()) {
151         CORE_LOG_W("Child already belongs to the target scene.");
152         return {};
153     }
154     IEcsObject::Ptr eobj;
155     if (auto i = interface_cast<IEcsObjectAccess>(node)) {
156         eobj = i->GetEcsObject();
157     }
158     if (eobj) {
159         if (auto s = GetInternalScene()) {
160             return s->AddTask([=] {
161                 auto ent = CopyExternalAsChild(*object_, *eobj);
162                 return CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
163             });
164         }
165     }
166     return {};
167 }
168 
ImportChildScene(const IScene::ConstPtr & scene,BASE_NS::string_view nodeName)169 Future<INode::Ptr> Node::ImportChildScene(const IScene::ConstPtr& scene, BASE_NS::string_view nodeName)
170 {
171     if (auto s = GetInternalScene(); s && scene) {
172         if (scene != GetScene()) {
173             return s->AddTask([=, name = BASE_NS::string(nodeName)] {
174                 BASE_NS::vector<CORE_NS::Entity> imported;
175                 auto ent = CopyExternalAsChild(*object_, *scene, imported);
176                 auto node = CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
177                 if (auto named = interface_cast<META_NS::INamed>(node)) {
178                     named->Name()->SetValue(name);
179                     SyncProperty(s, named->Name());
180                 }
181                 if (auto import = interface_cast<INodeImport>(node)) {
182                     import->TrackImportedEntities(imported);
183                 }
184                 return node;
185             });
186         }
187         CORE_LOG_E("Cannot import a scene into itself.");
188     }
189     return {};
190 }
191 
ImportChildScene(BASE_NS::string_view uri,BASE_NS::string_view nodeName)192 Future<INode::Ptr> Node::ImportChildScene(BASE_NS::string_view uri, BASE_NS::string_view nodeName)
193 {
194     if (auto s = GetInternalScene()) {
195         return s->AddTask([=, uri = BASE_NS::string(uri), name = BASE_NS::string(nodeName)] {
196             if (auto provider = interface_cast<IApplicationContextProvider>(s)) {
197                 if (auto appContext = provider->GetApplicationContext()) {
198                     if (auto manager = appContext->GetSceneManager()) {
199                         auto scene = manager->CreateScene(uri, s->GetOptions()).GetResult();
200                         return ImportChildScene(scene, name).GetResult();
201                     }
202                 }
203             }
204             return INode::Ptr {};
205         });
206     }
207     return {};
208 }
209 
210 template<typename Func>
IterateImpl(const BASE_NS::vector<INode::Ptr> & cont,const Func & func)211 static META_NS::IterationResult IterateImpl(const BASE_NS::vector<INode::Ptr>& cont, const Func& func)
212 {
213     for (auto&& child : cont) {
214         if (auto obj = interface_pointer_cast<META_NS::IObject>(child)) {
215             auto res = func->Invoke(obj);
216             if (!res.Continue()) {
217                 return res;
218             }
219         }
220     }
221     return META_NS::IterationResult::CONTINUE;
222 }
223 
224 // --- IIterable
Iterate(const META_NS::IterationParameters & params)225 META_NS::IterationResult Node::Iterate(const META_NS::IterationParameters& params)
226 {
227     auto f = params.function.GetInterface<META_NS::IIterableCallable<META_NS::IObject::Ptr>>();
228     if (!f) {
229         CORE_LOG_W("Incompatible function with Iterate");
230         return META_NS::IterationResult::FAILED;
231     }
232     return IterateImpl(GetChildren().GetResult(), f);
233 }
Iterate(const META_NS::IterationParameters & params) const234 META_NS::IterationResult Node::Iterate(const META_NS::IterationParameters& params) const
235 {
236     auto f = params.function.GetInterface<META_NS::IIterableConstCallable<META_NS::IObject::Ptr>>();
237     if (!f) {
238         CORE_LOG_W("Incompatible function with Iterate");
239         return META_NS::IterationResult::FAILED;
240     }
241     return IterateImpl(GetChildren().GetResult(), f);
242 }
243 // --- IIterable
244 
245 // --- IContainer
GetAll() const246 BASE_NS::vector<META_NS::IObject::Ptr> Node::GetAll() const
247 {
248     return META_NS::PtrArrayCast<IObject>(GetChildren().GetResult());
249 }
GetAt(SizeType index) const250 META_NS::IObject::Ptr Node::GetAt(SizeType index) const
251 {
252     auto children = GetChildren().GetResult();
253     return index < children.size() ? interface_pointer_cast<IObject>(children[index]) : nullptr;
254 }
GetSize() const255 META_NS::IContainer::SizeType Node::GetSize() const
256 {
257     return GetChildren().GetResult().size();
258 }
MatchCriteria(const META_NS::IContainer::FindOptions & options,const META_NS::IObject::Ptr & object)259 static bool MatchCriteria(const META_NS::IContainer::FindOptions& options, const META_NS::IObject::Ptr& object)
260 {
261     return object && (options.name.empty() || object->GetName() == options.name) &&
262            META_NS::CheckInterfaces(object, options.uids, options.strict);
263 }
FindAll(const FindOptions & options) const264 BASE_NS::vector<META_NS::IObject::Ptr> Node::FindAll(const FindOptions& options) const
265 {
266     BASE_NS::vector<IObject::Ptr> res;
267     META_NS::Internal::ConstIterate(
268         this,
269         [&](const IObject::Ptr& obj) {
270             if (MatchCriteria(options, obj)) {
271                 res.push_back(obj);
272             }
273             return true;
274         },
275         META_NS::IterateStrategy { options.behavior, META_NS::LockType::SHARED_LOCK });
276     return res;
277 }
FindAny(const FindOptions & options) const278 META_NS::IObject::Ptr Node::FindAny(const FindOptions& options) const
279 {
280     IObject::Ptr res;
281     META_NS::Internal::ConstIterate(
282         this,
283         [&](const IObject::Ptr& obj) {
284             if (MatchCriteria(options, obj)) {
285                 res = obj;
286             }
287             return !res;
288         },
289         META_NS::IterateStrategy { options.behavior, META_NS::LockType::SHARED_LOCK });
290     return res;
291 }
FindByName(BASE_NS::string_view name) const292 META_NS::IObject::Ptr Node::FindByName(BASE_NS::string_view name) const
293 {
294     return FindAny({ BASE_NS::string(name), META_NS::TraversalType::NO_HIERARCHY });
295 }
Add(const META_NS::IObject::Ptr & object)296 bool Node::Add(const META_NS::IObject::Ptr& object)
297 {
298     if (auto n = interface_pointer_cast<INode>(object)) {
299         return AddChild(n).GetResult();
300     }
301     return false;
302 }
Insert(SizeType index,const META_NS::IObject::Ptr & object)303 bool Node::Insert(SizeType index, const META_NS::IObject::Ptr& object)
304 {
305     if (auto n = interface_pointer_cast<INode>(object)) {
306         return AddChild(n, index).GetResult();
307     }
308     return false;
309 }
Remove(SizeType index)310 bool Node::Remove(SizeType index)
311 {
312     if (auto s = GetInternalScene()) {
313         return s
314             ->AddTask([&] {
315                 auto obj = GetAt(index);
316                 return obj && Remove(obj);
317             })
318             .GetResult();
319     }
320     return false;
321 }
Remove(const META_NS::IObject::Ptr & child)322 bool Node::Remove(const META_NS::IObject::Ptr& child)
323 {
324     if (auto n = interface_pointer_cast<INode>(child)) {
325         return RemoveChild(n).GetResult();
326     }
327     return false;
328 }
Move(SizeType fromIndex,SizeType toIndex)329 bool Node::Move(SizeType fromIndex, SizeType toIndex)
330 {
331     if (auto s = object_->GetScene()) {
332         return s
333             ->AddTask([&] {
334                 auto obj = GetAt(fromIndex);
335                 return Move(obj, toIndex);
336             })
337             .GetResult();
338     }
339     return false;
340 }
Move(const META_NS::IObject::Ptr & child,SizeType toIndex)341 bool Node::Move(const META_NS::IObject::Ptr& child, SizeType toIndex)
342 {
343     if (auto s = object_->GetScene()) {
344         return s->AddTask([&] { return child && Remove(child) && Insert(toIndex, child); }).GetResult();
345     }
346     return false;
347 }
Replace(const META_NS::IObject::Ptr & child,const META_NS::IObject::Ptr & replaceWith,bool addAlways)348 bool Node::Replace(const META_NS::IObject::Ptr& child, const META_NS::IObject::Ptr& replaceWith, bool addAlways)
349 {
350     if (auto s = object_->GetScene()) {
351         return s
352             ->AddTask([&] {
353                 auto vec = GetAll();
354                 size_t index = 0;
355                 for (; index < vec.size(); ++index) {
356                     if (vec[index] == child) {
357                         break;
358                     }
359                 }
360                 if (index == vec.size()) {
361                     if (addAlways) {
362                         Add(replaceWith);
363                         return true;
364                     }
365                     return false;
366                 }
367                 return Remove(index) && Insert(index, replaceWith);
368             })
369             .GetResult();
370     }
371     return false;
372 }
RemoveAll()373 void Node::RemoveAll()
374 {
375     if (auto s = object_->GetScene()) {
376         s->AddTask([&] {
377              for (auto&& c : GetAll()) {
378                  Remove(c);
379              }
380          }).Wait();
381     }
382 }
IsAncestorOf(const META_NS::IObject::ConstPtr & object) const383 bool Node::IsAncestorOf(const META_NS::IObject::ConstPtr& object) const
384 {
385     if (auto s = object_->GetScene()) {
386         return s
387             ->AddTask([&] {
388                 auto node = interface_pointer_cast<INode>(object);
389                 auto self = GetSelf<INode>();
390                 do {
391                     if (node == self) {
392                         return true;
393                     }
394                     if (node) {
395                         node = node->GetParent().GetResult();
396                     }
397                 } while (node);
398                 return false;
399             })
400             .GetResult();
401     }
402     return false;
403 }
404 
GetParent(ContainableTag) const405 META_NS::IObject::Ptr Node::GetParent(ContainableTag) const
406 {
407     return interface_pointer_cast<META_NS::IObject>(GetParent(NodeTag {}).GetResult());
408 }
409 
410 // --- IContainer
411 
OnMetadataConstructed(const META_NS::StaticMetadata & m,CORE_NS::IInterface & i)412 void Node::OnMetadataConstructed(const META_NS::StaticMetadata& m, CORE_NS::IInterface& i)
413 {
414     if (BASE_NS::string_view("OnContainerChanged") == m.name) {
415         if (auto s = object_->GetScene()) {
416             s->AddTask([&] { s->ListenNodeChanges(true); }).Wait();
417         }
418     }
419 }
420 
OnChildChanged(META_NS::ContainerChangeType type,const INode::Ptr & child,size_t index)421 void Node::OnChildChanged(META_NS::ContainerChangeType type, const INode::Ptr& child, size_t index)
422 {
423     if (auto event = GetEvent("OnContainerChanged", META_NS::MetadataQuery::EXISTING)) {
424         if (auto s = object_->GetScene()) {
425             META_NS::ChildChangedInfo info { type, interface_pointer_cast<META_NS::IObject>(child),
426                 GetSelf<META_NS::IContainer>() };
427             if (type == META_NS::ContainerChangeType::ADDED) {
428                 info.to = index;
429             }
430             if (type == META_NS::ContainerChangeType::REMOVED) {
431                 info.from = index;
432             }
433             s->InvokeUserNotification<META_NS::IOnChildChanged>(event, info);
434         }
435     }
436 }
437 
TrackImportedEntities(BASE_NS::array_view<const CORE_NS::Entity> entities)438 void Node::TrackImportedEntities(BASE_NS::array_view<const CORE_NS::Entity> entities)
439 {
440     imported_.insert(imported_.end(), entities.begin(), entities.end());
441 }
442 
IsListening() const443 bool Node::IsListening() const
444 {
445     return GetEvent("OnContainerChanged", META_NS::MetadataQuery::EXISTING) != nullptr;
446 }
447 
OnNodeActiveStateChanged(NodeActiteStateInfo state)448 void Node::OnNodeActiveStateChanged(NodeActiteStateInfo state)
449 {
450     if (startableHandler_) {
451         if (state == NodeActiteStateInfo::ACTIVATED) {
452             startableHandler_->StartAll(StartableHandler::StartType::DEFERRED);
453         } else if (state == NodeActiteStateInfo::DEACTIVATING) {
454             startableHandler_->StopAll();
455         }
456     }
457 }
458 
IsEnabledInHierarchy() const459 Future<bool> Node::IsEnabledInHierarchy() const
460 {
461     if (auto s = GetInternalScene()) {
462         return s->AddTask([=, ent = GetEntity()] {
463             auto& ecs = s->GetEcsContext();
464             if (auto c =
465                     static_cast<CORE3D_NS::INodeComponentManager*>(ecs.FindComponent<CORE3D_NS::NodeComponent>())) {
466                 if (auto v = c->Read(ent)) {
467                     return v->effectivelyEnabled;
468                 }
469             }
470             return false;
471         });
472     }
473     return {};
474 }
475 
476 SCENE_END_NAMESPACE()
477