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_system.h"
17 
18 #include <PropertyTools/property_api_impl.inl>
19 #include <cinttypes>
20 #include <cstdlib>
21 #include <utility>
22 
23 #include <3d/ecs/components/local_matrix_component.h>
24 #include <3d/ecs/components/name_component.h>
25 #include <3d/ecs/components/node_component.h>
26 #include <3d/ecs/components/transform_component.h>
27 #include <3d/ecs/components/world_matrix_component.h>
28 #include <base/containers/unordered_map.h>
29 #include <core/ecs/intf_ecs.h>
30 #include <core/ecs/intf_entity_manager.h>
31 #include <core/log.h>
32 #include <core/namespace.h>
33 
34 #include "ecs/components/previous_world_matrix_component.h"
35 #include "util/string_util.h"
36 
37 CORE_BEGIN_NAMESPACE()
38 bool operator<(const Entity& lhs, const Entity& rhs)
39 {
40     return lhs.id < rhs.id;
41 }
42 CORE_END_NAMESPACE()
43 
44 CORE3D_BEGIN_NAMESPACE()
45 using namespace BASE_NS;
46 using namespace CORE_NS;
47 
48 namespace {
49 constexpr auto NODE_INDEX = 0U;
50 constexpr auto LOCAL_INDEX = 1U;
51 constexpr auto PREV_WORLD_INDEX = 2U;
52 constexpr auto WORLD_INDEX = 3U;
53 
54 template<class T>
RecursivelyLookupNodeByPath(T & node,size_t index,const vector<string_view> & path)55 T* RecursivelyLookupNodeByPath(T& node, size_t index, const vector<string_view>& path)
56 {
57     // Access to children will automatically refresh cache.
58     // Loop through all childs, see if there is a node with given name.
59     // If found, then recurse in to that node branch and see if lookup is able to complete in that branch.
60     for (T* child : node.GetChildren()) {
61         if (child && child->GetName() == path[index]) {
62             // Found node with requested name, lookup completed?
63             if (index + 1 >= path.size()) {
64                 return child;
65             }
66 
67             // Continue lookup recursively.
68             T* result = RecursivelyLookupNodeByPath(*child, index + 1, path);
69             if (result) {
70                 // We have a hit.
71                 return result;
72             }
73         }
74     }
75 
76     // No hit.
77     return nullptr;
78 }
79 
80 template<class T>
RecursivelyLookupNodeByName(T & node,string_view name)81 T* RecursivelyLookupNodeByName(T& node, string_view name)
82 {
83     if (name.compare(node.GetName()) == 0) {
84         return &node;
85     }
86 
87     // Access to children will automatically refresh cache.
88     // Loop through all childs, see if there is a node with given name.
89     for (T* child : node.GetChildren()) {
90         if (child) {
91             // Continue lookup recursively.
92             T* result = RecursivelyLookupNodeByName(*child, name);
93             if (result) {
94                 // We have a hit.
95                 return result;
96             }
97         }
98     }
99 
100     // No hit.
101     return nullptr;
102 }
103 
104 template<class T>
RecursivelyLookupNodesByComponent(T & node,const IComponentManager & componentManager,vector<T * > & results,bool singleNodeLookup)105 bool RecursivelyLookupNodesByComponent(
106     T& node, const IComponentManager& componentManager, vector<T*>& results, bool singleNodeLookup)
107 {
108     bool result = false;
109     if (componentManager.HasComponent(node.GetEntity())) {
110         result = true;
111         results.push_back(&node);
112         if (singleNodeLookup) {
113             return result;
114         }
115     }
116 
117     // Access to children will automatically refresh cache.
118     // Loop through all childs, see if there is a node with given name.
119     // If found, then recurse in to that node branch and see if lookup is able to complete in that branch.
120     for (T* child : node.GetChildren()) {
121         if (child) {
122             // Continue lookup recursively.
123             if (RecursivelyLookupNodesByComponent(*child, componentManager, results, singleNodeLookup)) {
124                 result = true;
125                 if (singleNodeLookup) {
126                     return result;
127                 }
128             }
129         }
130     }
131 
132     return result;
133 }
134 
135 template<typename ListType, typename ValueType>
Find(ListType && list,ValueType && value)136 inline auto Find(ListType&& list, ValueType&& value)
137 {
138     return std::find(list.begin(), list.end(), BASE_NS::forward<ValueType>(value));
139 }
140 
141 template<typename ListType, typename Predicate>
FindIf(ListType && list,Predicate && pred)142 inline auto FindIf(ListType&& list, Predicate&& pred)
143 {
144     return std::find_if(list.begin(), list.end(), BASE_NS::forward<Predicate>(pred));
145 }
146 } // namespace
147 
148 // Interface that allows nodes to access other nodes and request cache updates.
149 class NodeSystem::NodeAccess {
150 public:
151     virtual ~NodeAccess() = default;
152 
153     virtual string GetName(Entity entity) const = 0;
154     virtual void SetName(Entity entity, string_view name) = 0;
155 
156     virtual Math::Vec3 GetPosition(Entity entity) const = 0;
157     virtual Math::Quat GetRotation(Entity entity) const = 0;
158     virtual Math::Vec3 GetScale(Entity entity) const = 0;
159     virtual void SetScale(Entity entity, const Math::Vec3& scale) = 0;
160     virtual void SetPosition(Entity entity, const Math::Vec3& position) = 0;
161     virtual void SetRotation(Entity entity, const Math::Quat& rotation) = 0;
162 
163     virtual bool GetEnabled(Entity entity) const = 0;
164     virtual void SetEnabled(Entity entity, bool isEnabled) = 0;
165     virtual bool GetEffectivelyEnabled(Entity entity) const = 0;
166     virtual ISceneNode* GetParent(Entity entity) const = 0;
167     virtual void SetParent(Entity entity, ISceneNode const& node) = 0;
168 
169     virtual void Notify(const ISceneNode& parent, NodeSystem::SceneNodeListener::EventType type,
170         const ISceneNode& child, size_t index) = 0;
171 
172     virtual NodeSystem::SceneNode* GetNode(Entity const& entity) const = 0;
173     virtual void Refresh() = 0;
174 };
175 
176 // Implementation of the node interface.
177 class NodeSystem::SceneNode : public ISceneNode {
178 public:
179     struct NodeState {
180         Entity parent { 0 };
181         uint32_t localMatrixGeneration { 0 };
182         bool enabled { false };
183         bool parentChanged { false };
184     };
185 
186     SceneNode(const SceneNode& other) = delete;
187     SceneNode& operator=(const SceneNode& node) = delete;
188 
SceneNode(Entity entity,NodeAccess & nodeAccess)189     SceneNode(Entity entity, NodeAccess& nodeAccess) : entity_(entity), nodeAccess_(nodeAccess) {}
190 
191     ~SceneNode() override = default;
192 
GetName() const193     string GetName() const override
194     {
195         return nodeAccess_.GetName(entity_);
196     }
197 
SetName(const string_view name)198     void SetName(const string_view name) override
199     {
200         nodeAccess_.SetName(entity_, name);
201     }
202 
SetEnabled(bool isEnabled)203     void SetEnabled(bool isEnabled) override
204     {
205         nodeAccess_.SetEnabled(entity_, isEnabled);
206     }
207 
GetEnabled() const208     bool GetEnabled() const override
209     {
210         return nodeAccess_.GetEnabled(entity_);
211     }
212 
GetEffectivelyEnabled() const213     bool GetEffectivelyEnabled() const override
214     {
215         return nodeAccess_.GetEffectivelyEnabled(entity_);
216     }
217 
GetParent() const218     ISceneNode* GetParent() const override
219     {
220         if (!EntityUtil::IsValid(entity_)) {
221             return nullptr;
222         }
223 
224         nodeAccess_.Refresh();
225 
226         return nodeAccess_.GetParent(entity_);
227     }
228 
SetParent(ISceneNode const & node)229     void SetParent(ISceneNode const& node) override
230     {
231         nodeAccess_.Refresh();
232 
233         // Ensure we are not ancestors of the new parent.
234         CORE_ASSERT(IsAncestorOf(node) == false);
235 
236         nodeAccess_.SetParent(entity_, node);
237     }
238 
IsAncestorOf(ISceneNode const & node)239     bool IsAncestorOf(ISceneNode const& node) override
240     {
241         nodeAccess_.Refresh();
242 
243         ISceneNode const* curNode = &node;
244         while (curNode != nullptr) {
245             if (curNode == this) {
246                 return true;
247             }
248             const auto currEntity = curNode->GetEntity();
249 
250             curNode = EntityUtil::IsValid(currEntity) ? nodeAccess_.GetParent(currEntity) : nullptr;
251         }
252 
253         return false;
254     }
255 
GetChildren() const256     array_view<ISceneNode* const> GetChildren() const override
257     {
258         nodeAccess_.Refresh();
259         return { reinterpret_cast<ISceneNode* const*>(children_.data()), children_.size() };
260     }
261 
GetChildren()262     array_view<ISceneNode*> GetChildren() override
263     {
264         nodeAccess_.Refresh();
265         return array_view(reinterpret_cast<ISceneNode**>(children_.data()), children_.size());
266     }
267 
GetEntity() const268     Entity GetEntity() const override
269     {
270         return entity_;
271     }
272 
GetChild(string_view const & name) const273     const ISceneNode* GetChild(string_view const& name) const override
274     {
275         // Access to children will automatically refresh cache.
276         auto children = GetChildren();
277         if (auto pos =
278                 FindIf(children, [name](const ISceneNode* child) { return child && (child->GetName() == name); });
279             pos != children.end()) {
280             return *pos;
281         }
282 
283         return nullptr;
284     }
285 
GetChild(string_view const & name)286     ISceneNode* GetChild(string_view const& name) override
287     {
288         // Access to children will automatically refresh cache.
289         auto children = GetChildren();
290         if (auto pos =
291                 FindIf(children, [name](const ISceneNode* child) { return child && (child->GetName() == name); });
292             pos != children.end()) {
293             return *pos;
294         }
295 
296         return nullptr;
297     }
298 
AddChild(ISceneNode & node)299     bool AddChild(ISceneNode& node) override
300     {
301         auto children = GetChildren();
302         if (auto pos = Find(children, &node); pos == children.end()) {
303             nodeAccess_.SetParent(node.GetEntity(), *this);
304             nodeAccess_.Notify(*this, INodeSystem::SceneNodeListener::EventType::ADDED, node, children_.size() - 1U);
305             return true;
306         }
307         return false;
308     }
309 
InsertChild(size_t index,ISceneNode & node)310     bool InsertChild(size_t index, ISceneNode& node) override
311     {
312         const auto children = GetChildren();
313         if (auto pos = Find(children, &node); pos == children.cend()) {
314             nodeAccess_.SetParent(node.GetEntity(), *this);
315             if (index < children_.size()) {
316                 std::rotate(children_.begin() + static_cast<ptrdiff_t>(index), children_.end() - 1, children_.end());
317             } else {
318                 index = children_.size() - 1U;
319             }
320             nodeAccess_.Notify(*this, INodeSystem::SceneNodeListener::EventType::ADDED, node, index);
321             return true;
322         }
323         return false;
324     }
325 
RemoveChild(ISceneNode & node)326     bool RemoveChild(ISceneNode& node) override
327     {
328         if (EntityUtil::IsValid(entity_)) {
329             const auto children = GetChildren();
330             if (auto pos = Find(children, &node); pos != children.cend()) {
331                 const auto index = pos - children.begin();
332                 nodeAccess_.SetParent(node.GetEntity(), *nodeAccess_.GetNode({}));
333                 nodeAccess_.Notify(
334                     *this, INodeSystem::SceneNodeListener::EventType::REMOVED, node, static_cast<size_t>(index));
335                 return true;
336             }
337         }
338         return false;
339     }
340 
RemoveChild(size_t index)341     bool RemoveChild(size_t index) override
342     {
343         if (EntityUtil::IsValid(entity_) && !children_.empty()) {
344             nodeAccess_.Refresh();
345             if (index < children_.size()) {
346                 if (auto* node = children_[index]) {
347                     nodeAccess_.SetParent(node->GetEntity(), *nodeAccess_.GetNode({}));
348                     nodeAccess_.Notify(*this, INodeSystem::SceneNodeListener::EventType::REMOVED, *node, index);
349                     return true;
350                 } else {
351                     CORE_LOG_W("Node %" PRIx64 " with null child at %zu", entity_.id, index);
352                     children_.erase(children_.cbegin() + static_cast<ptrdiff_t>(index));
353                 }
354             }
355         }
356         return false;
357     }
358 
RemoveChildren()359     bool RemoveChildren() override
360     {
361         if (EntityUtil::IsValid(entity_) && !children_.empty()) {
362             auto root = nodeAccess_.GetNode({});
363             while (!children_.empty()) {
364                 if (auto* node = children_.back()) {
365                     const auto index = children_.size() - 1U;
366                     nodeAccess_.SetParent(node->entity_, *root);
367                     nodeAccess_.Notify(*this, INodeSystem::SceneNodeListener::EventType::REMOVED, *node, index);
368                 } else {
369                     CORE_LOG_W("Node %" PRIx64 " with null child at %zu", entity_.id, children_.size() - 1U);
370                     children_.pop_back();
371                 }
372             }
373             return true;
374         }
375         return false;
376     }
377 
LookupNodeByPath(string_view const & path) const378     const ISceneNode* LookupNodeByPath(string_view const& path) const override
379     {
380         // Split path to array of node names.
381         vector<string_view> parts = StringUtil::Split(path, "/");
382         if (parts.size() > 0) {
383             // Perform lookup using array of names and 'current' index (start from zero).
384             return RecursivelyLookupNodeByPath<const ISceneNode>(*this, 0, parts);
385         }
386 
387         return nullptr;
388     }
389 
LookupNodeByPath(string_view const & path)390     ISceneNode* LookupNodeByPath(string_view const& path) override
391     {
392         // Split path to array of node names.
393         vector<string_view> parts = StringUtil::Split(path, "/");
394         if (parts.size() > 0) {
395             // Perform lookup using array of names and 'current' index (start from zero).
396             return RecursivelyLookupNodeByPath<ISceneNode>(*this, 0, parts);
397         }
398 
399         return nullptr;
400     }
401 
LookupNodeByName(string_view const & name) const402     const ISceneNode* LookupNodeByName(string_view const& name) const override
403     {
404         return RecursivelyLookupNodeByName<const ISceneNode>(*this, name);
405     }
406 
LookupNodeByName(string_view const & name)407     ISceneNode* LookupNodeByName(string_view const& name) override
408     {
409         return RecursivelyLookupNodeByName<ISceneNode>(*this, name);
410     }
411 
LookupNodeByComponent(const IComponentManager & componentManager) const412     const ISceneNode* LookupNodeByComponent(const IComponentManager& componentManager) const override
413     {
414         vector<const ISceneNode*> results;
415         if (RecursivelyLookupNodesByComponent<const ISceneNode>(*this, componentManager, results, true)) {
416             return results[0];
417         }
418 
419         return nullptr;
420     }
421 
LookupNodeByComponent(const IComponentManager & componentManager)422     ISceneNode* LookupNodeByComponent(const IComponentManager& componentManager) override
423     {
424         vector<ISceneNode*> results;
425         if (RecursivelyLookupNodesByComponent<ISceneNode>(*this, componentManager, results, true)) {
426             return results[0];
427         }
428 
429         return nullptr;
430     }
431 
LookupNodesByComponent(const IComponentManager & componentManager) const432     vector<const ISceneNode*> LookupNodesByComponent(const IComponentManager& componentManager) const override
433     {
434         vector<const ISceneNode*> results;
435         RecursivelyLookupNodesByComponent<const ISceneNode>(*this, componentManager, results, false);
436         return results;
437     }
438 
LookupNodesByComponent(const IComponentManager & componentManager)439     vector<ISceneNode*> LookupNodesByComponent(const IComponentManager& componentManager) override
440     {
441         vector<ISceneNode*> results;
442         RecursivelyLookupNodesByComponent<ISceneNode>(*this, componentManager, results, false);
443         return results;
444     }
445 
GetPosition() const446     Math::Vec3 GetPosition() const override
447     {
448         return nodeAccess_.GetPosition(entity_);
449     }
450 
GetRotation() const451     Math::Quat GetRotation() const override
452     {
453         return nodeAccess_.GetRotation(entity_);
454     }
455 
GetScale() const456     Math::Vec3 GetScale() const override
457     {
458         return nodeAccess_.GetScale(entity_);
459     }
460 
SetScale(const Math::Vec3 & scale)461     void SetScale(const Math::Vec3& scale) override
462     {
463         return nodeAccess_.SetScale(entity_, scale);
464     }
465 
SetPosition(const Math::Vec3 & position)466     void SetPosition(const Math::Vec3& position) override
467     {
468         nodeAccess_.SetPosition(entity_, position);
469     }
470 
SetRotation(const Math::Quat & rotation)471     void SetRotation(const Math::Quat& rotation) override
472     {
473         nodeAccess_.SetRotation(entity_, rotation);
474     }
475 
476     // Internally for NodeSystem to skip unneccessary NodeCache::Refresh calls
PopChildNoRefresh()477     SceneNode* PopChildNoRefresh()
478     {
479         if (children_.empty()) {
480             return nullptr;
481         } else {
482             auto child = children_.back();
483             children_.pop_back();
484             return child;
485         }
486     }
487 
488 private:
489     const Entity entity_;
490 
491     NodeAccess& nodeAccess_;
492 
493     vector<SceneNode*> children_;
494     NodeState lastState_ {};
495 
496     friend NodeSystem;
497     friend NodeSystem::NodeCache;
498 };
499 
500 // Cache for nodes.
501 class NodeSystem::NodeCache final : public NodeAccess {
502 public:
NodeCache(IEntityManager & entityManager,INameComponentManager & nameComponentManager,INodeComponentManager & nodeComponentManager,ITransformComponentManager & transformComponentManager)503     NodeCache(IEntityManager& entityManager, INameComponentManager& nameComponentManager,
504         INodeComponentManager& nodeComponentManager, ITransformComponentManager& transformComponentManager)
505         : nameComponentManager_(nameComponentManager), nodeComponentManager_(nodeComponentManager),
506           transformComponentManager_(transformComponentManager), entityManager_(entityManager)
507     {
508         // Add root node.
509         AddNode(Entity());
510     }
511 
512     ~NodeCache() override = default;
513 
Reset()514     void Reset()
515     {
516         const auto first = nodeEntities_.cbegin();
517         const auto last = nodeEntities_.cend();
518         if (auto pos = std::lower_bound(
519                 first, last, Entity(), [](const Entity& lhs, const Entity& rhs) { return lhs.id < rhs.id; });
520             (pos != last) && (*pos == Entity())) {
521             const auto index = static_cast<size_t>(pos - first);
522             auto rootNode = move(nodes_[index]);
523             rootNode->children_.clear();
524             nodes_.clear();
525             nodes_.push_back(move(rootNode));
526             nodeEntities_.clear();
527             nodeEntities_.push_back(Entity());
528             auto entry = lookUp_.extract(Entity());
529             lookUp_.clear();
530             lookUp_.insert(move(entry));
531         }
532     }
533 
AddNode(Entity const & entity)534     SceneNode* AddNode(Entity const& entity)
535     {
536         SceneNode* result;
537 
538         auto node = make_unique<SceneNode>(entity, *this);
539         result = node.get();
540         const auto first = nodeEntities_.cbegin();
541         const auto last = nodeEntities_.cend();
542         auto pos =
543             std::lower_bound(first, last, entity, [](const Entity& lhs, const Entity& rhs) { return lhs.id < rhs.id; });
544         const auto index = pos - first;
545         if ((pos == last) || (*pos != entity)) {
546             nodeEntities_.insert(pos, entity);
547             lookUp_[entity] = node.get();
548             nodes_.insert(nodes_.cbegin() + index, move(node));
549         } else {
550             lookUp_[entity] = node.get();
551             nodes_[static_cast<size_t>(index)] = move(node);
552         }
553 
554         if (auto handle = nodeComponentManager_.Read(entity)) {
555             if (auto* parent = GetNode(handle->parent)) {
556                 // Set parent / child relationship.
557                 parent->children_.push_back(result);
558                 result->lastState_.parent = handle->parent;
559             }
560             result->lastState_.parentChanged = true;
561         }
562 
563         // check if some node thinks it should be the child of the new node and it there.
564         for (const auto& nodePtr : nodes_) {
565             if (nodePtr->lastState_.parent == entity) {
566                 result->children_.push_back(nodePtr.get());
567             }
568         }
569 
570         return result;
571     }
572 
GetName(const Entity entity) const573     string GetName(const Entity entity) const override
574     {
575         if (const auto nameId = nameComponentManager_.GetComponentId(entity);
576             nameId != IComponentManager::INVALID_COMPONENT_ID) {
577             return nameComponentManager_.Get(entity).name;
578         } else {
579             return "";
580         }
581     }
582 
SetName(const Entity entity,const string_view name)583     void SetName(const Entity entity, const string_view name) override
584     {
585         if (ScopedHandle<NameComponent> data = nameComponentManager_.Write(entity); data) {
586             data->name = name;
587         }
588     }
589 
GetPosition(const Entity entity) const590     Math::Vec3 GetPosition(const Entity entity) const override
591     {
592         if (const auto nameId = transformComponentManager_.GetComponentId(entity);
593             nameId != IComponentManager::INVALID_COMPONENT_ID) {
594             return transformComponentManager_.Get(entity).position;
595         } else {
596             return Math::Vec3();
597         }
598     }
599 
GetRotation(const Entity entity) const600     Math::Quat GetRotation(const Entity entity) const override
601     {
602         if (const auto nameId = transformComponentManager_.GetComponentId(entity);
603             nameId != IComponentManager::INVALID_COMPONENT_ID) {
604             return transformComponentManager_.Get(entity).rotation;
605         } else {
606             return Math::Quat();
607         }
608     }
609 
GetScale(const Entity entity) const610     Math::Vec3 GetScale(const Entity entity) const override
611     {
612         if (const auto nameId = transformComponentManager_.GetComponentId(entity);
613             nameId != IComponentManager::INVALID_COMPONENT_ID) {
614             return transformComponentManager_.Get(entity).scale;
615         } else {
616             return Math::Vec3 { 1.0f, 1.0f, 1.0f };
617         }
618     }
619 
SetScale(const Entity entity,const Math::Vec3 & scale)620     void SetScale(const Entity entity, const Math::Vec3& scale) override
621     {
622         if (ScopedHandle<TransformComponent> data = transformComponentManager_.Write(entity); data) {
623             data->scale = scale;
624         }
625     }
626 
SetPosition(const Entity entity,const Math::Vec3 & position)627     void SetPosition(const Entity entity, const Math::Vec3& position) override
628     {
629         if (ScopedHandle<TransformComponent> data = transformComponentManager_.Write(entity); data) {
630             data->position = position;
631         }
632     }
633 
SetRotation(const Entity entity,const Math::Quat & rotation)634     void SetRotation(const Entity entity, const Math::Quat& rotation) override
635     {
636         if (ScopedHandle<TransformComponent> data = transformComponentManager_.Write(entity); data) {
637             data->rotation = rotation;
638         }
639     }
640 
GetEnabled(const Entity entity) const641     bool GetEnabled(const Entity entity) const override
642     {
643         bool enabled = true;
644         if (ScopedHandle<const NodeComponent> data = nodeComponentManager_.Read(entity); data) {
645             enabled = data->enabled;
646         }
647         return enabled;
648     }
649 
DisableTree(SceneNode * node,INodeComponentManager & nodeComponentManager)650     static void DisableTree(SceneNode* node, INodeComponentManager& nodeComponentManager)
651     {
652         BASE_NS::vector<SceneNode*> stack;
653         stack.push_back(node);
654 
655         while (!stack.empty()) {
656             auto current = stack.back();
657             stack.pop_back();
658             if (!current) {
659                 continue;
660             }
661             auto* handle = nodeComponentManager.GetData(current->entity_);
662             if (!handle) {
663                 continue;
664             }
665             // if a node is effectively enabled, update and add children. otherwise we can assume the node had been
666             // disabled earlier and its children are already disabled.
667             if (ScopedHandle<const NodeComponent>(handle)->effectivelyEnabled) {
668                 ScopedHandle<NodeComponent>(handle)->effectivelyEnabled = false;
669                 stack.append(current->children_.cbegin(), current->children_.cend());
670             }
671         }
672     }
673 
EnableTree(SceneNode * node,INodeComponentManager & nodeComponentManager)674     static void EnableTree(SceneNode* node, INodeComponentManager& nodeComponentManager)
675     {
676         BASE_NS::vector<SceneNode*> stack;
677         stack.push_back(node);
678 
679         while (!stack.empty()) {
680             auto current = stack.back();
681             stack.pop_back();
682             if (!current) {
683                 continue;
684             }
685             auto* childHandle = nodeComponentManager.GetData(current->entity_);
686             if (!childHandle) {
687                 continue;
688             }
689             // if a node is enabled, update and add children. otherwise the node and its children remain effectivaly
690             // disabled.
691             if (ScopedHandle<const NodeComponent>(childHandle)->enabled) {
692                 ScopedHandle<NodeComponent>(childHandle)->effectivelyEnabled = true;
693                 stack.append(current->children_.cbegin(), current->children_.cend());
694             }
695         }
696     }
697 
SetEnabled(const Entity entity,const bool isEnabled)698     void SetEnabled(const Entity entity, const bool isEnabled) override
699     {
700         auto* handle = nodeComponentManager_.GetData(entity);
701         if (!handle) {
702             return;
703         }
704         const auto nodeComponent = *ScopedHandle<const NodeComponent>(handle);
705         if (nodeComponent.enabled == isEnabled) {
706             return;
707         }
708 
709         ScopedHandle<NodeComponent>(handle)->enabled = isEnabled;
710 
711         const auto nodeGeneration = nodeComponentManager_.GetGenerationCounter();
712         if ((nodeComponentGenerationId_ + 1U) != nodeGeneration) {
713             // if generation count has changed, we can only update this node.
714             return;
715         }
716         nodeComponentGenerationId_ = nodeGeneration;
717 
718         if (isEnabled == nodeComponent.effectivelyEnabled) {
719             // if effectivelyEnabled matches the new state, there's no need to update the tree.
720             return;
721         }
722 
723         auto node = GetNode(entity);
724         if (!node) {
725             // if the node can't be found, we can only update this node.
726             return;
727         }
728 
729         if (!isEnabled) {
730             DisableTree(node, nodeComponentManager_);
731         } else if (auto parent = GetNode(nodeComponent.parent); !parent || !parent->GetEffectivelyEnabled()) {
732             // if the node's parent is disabled, there's no need to update the tree.
733             return;
734         } else {
735             EnableTree(node, nodeComponentManager_);
736         }
737 
738         nodeComponentGenerationId_ = nodeComponentManager_.GetGenerationCounter();
739     }
740 
GetEffectivelyEnabled(const Entity entity) const741     bool GetEffectivelyEnabled(const Entity entity) const override
742     {
743         bool effectivelyEnabled = true;
744         if (ScopedHandle<const NodeComponent> data = nodeComponentManager_.Read(entity); data) {
745             effectivelyEnabled = data->effectivelyEnabled;
746         }
747         return effectivelyEnabled;
748     }
749 
GetParent(const Entity entity) const750     ISceneNode* GetParent(const Entity entity) const override
751     {
752         Entity parent;
753         if (ScopedHandle<const NodeComponent> data = nodeComponentManager_.Read(entity); data) {
754             parent = data->parent;
755         }
756 
757         return GetNode(parent);
758     }
759 
SetParent(const Entity entity,ISceneNode const & node)760     void SetParent(const Entity entity, ISceneNode const& node) override
761     {
762         Entity oldParent;
763         const auto newParent = node.GetEntity();
764         const auto effectivelyEnabled = node.GetEffectivelyEnabled();
765         if (ScopedHandle<NodeComponent> data = nodeComponentManager_.Write(entity); data) {
766             oldParent = data->parent;
767             data->parent = newParent;
768             data->effectivelyEnabled = effectivelyEnabled;
769         }
770         UpdateParent(entity, oldParent, newParent);
771     }
772 
Notify(const ISceneNode & parent,NodeSystem::SceneNodeListener::EventType type,const ISceneNode & child,size_t index)773     void Notify(const ISceneNode& parent, NodeSystem::SceneNodeListener::EventType type, const ISceneNode& child,
774         size_t index) override
775     {
776         for (auto* listener : listeners_) {
777             if (listener) {
778                 listener->OnChildChanged(parent, type, child, index);
779             }
780         }
781     }
782 
GetNode(Entity const & entity) const783     SceneNode* GetNode(Entity const& entity) const override
784     {
785         auto pos = lookUp_.find(entity);
786         if (pos != lookUp_.end()) {
787             return pos->second;
788         }
789         return nullptr;
790     }
791 
UpdateParent(Entity entity,Entity oldParent,Entity newParent)792     void UpdateParent(Entity entity, Entity oldParent, Entity newParent)
793     {
794         const uint32_t nodeGenerationId = nodeComponentManager_.GetGenerationCounter();
795         if (nodeGenerationId <= (nodeComponentGenerationId_ + 1U)) {
796             nodeComponentGenerationId_ = nodeGenerationId;
797 
798             if (SceneNode* node = GetNode(entity)) {
799                 if (SceneNode* parent = GetNode(oldParent); parent) {
800                     parent->children_.erase(std::remove(parent->children_.begin(), parent->children_.end(), node),
801                         parent->children_.cend());
802                     node->lastState_.parent = {};
803                 }
804                 if (SceneNode* parent = GetNode(newParent); parent) {
805                     // Set parent / child relationship.
806                     parent->children_.push_back(node);
807                     node->lastState_.parent = newParent;
808                 }
809                 node->lastState_.parentChanged = true;
810             } else {
811                 CORE_LOG_W("Updating parent of invalid node %" PRIx64 " (old %" PRIx64 " new %" PRIx64 ")", entity.id,
812                     oldParent.id, newParent.id);
813             }
814         }
815     }
816 
Refresh()817     void Refresh() override
818     {
819         // If no modifications, then no need to refresh.
820         const uint32_t nodeGenerationId = nodeComponentManager_.GetGenerationCounter();
821         const uint32_t entityGenerationId = entityManager_.GetGenerationCounter();
822         if (nodeGenerationId == nodeComponentGenerationId_ && entityGenerationId == entityGenerationId_) {
823             return;
824         }
825 
826         vector<Entity> entitiesWithNode;
827         // allocate space for all entities + extra for collecting removed and added entities. worst case is that all
828         // the old ones have been removed and everything is new.
829         const auto nodeComponents = nodeComponentManager_.GetComponentCount();
830         entitiesWithNode.reserve((nodeComponents + nodeEntities_.size()) * 2U);
831         entitiesWithNode.resize(nodeComponents);
832         for (IComponentManager::ComponentId i = 0; i < nodeComponents; ++i) {
833             auto entity = nodeComponentManager_.GetEntity(i);
834             entitiesWithNode[i] = entity;
835         }
836 
837         auto first = entitiesWithNode.begin();
838         auto last = entitiesWithNode.end();
839 
840         // remove inactive entities
841         last = entitiesWithNode.erase(
842             std::remove_if(first, last, [&em = entityManager_](Entity entity) { return !em.IsAlive(entity); }), last);
843 
844         std::sort(first, last, [](Entity lhs, Entity rhs) { return lhs.id < rhs.id; });
845 
846         // there's at least the root (invalid/default constructed entity)
847         entitiesWithNode.insert(first, Entity());
848         last = entitiesWithNode.end();
849 
850         // Look up entities that no longer exist.
851         auto inserter = std::back_inserter(entitiesWithNode);
852         inserter = std::set_difference(nodeEntities_.cbegin(), nodeEntities_.cend(), first, last, inserter,
853             [](Entity lhs, Entity rhs) { return lhs.id < rhs.id; });
854 
855         auto lastRemoved = entitiesWithNode.end();
856 
857         // Look up entities that have been added.
858         inserter = std::set_difference(first, last, nodeEntities_.cbegin(), nodeEntities_.cend(), inserter,
859             [](Entity lhs, Entity rhs) { return lhs.id < rhs.id; });
860         auto lastAdded = entitiesWithNode.end();
861 
862         // Remove !alive entities and those without node component
863         std::for_each(last, lastRemoved, [this](Entity oldEntity) {
864             const auto first = nodeEntities_.cbegin();
865             const auto last = nodeEntities_.cend();
866             if (auto pos =
867                     std::lower_bound(first, last, oldEntity, [](Entity lhs, Entity rhs) { return lhs.id < rhs.id; });
868                 (pos != last) && (*pos == oldEntity)) {
869                 const auto index = pos - first;
870                 // detach the node from its parent before cleanup
871                 {
872                     auto* node = nodes_[static_cast<size_t>(index)].get();
873                     Entity parentEntity = static_cast<SceneNode*>(node)->lastState_.parent;
874                     if (auto parentIt = lookUp_.find(parentEntity); parentIt != lookUp_.end()) {
875                         auto& children = parentIt->second->children_;
876                         children.erase(std::remove(children.begin(), children.end(), node), children.cend());
877                     }
878                     // can we rely on lastState_.parent, or also check from node component?
879                     if (ScopedHandle<const NodeComponent> data = nodeComponentManager_.Read(oldEntity); data) {
880                         if (parentEntity != data->parent) {
881                             if (auto parentIt = lookUp_.find(data->parent); parentIt != lookUp_.end()) {
882                                 auto& children = parentIt->second->children_;
883                                 children.erase(std::remove(children.begin(), children.end(), node), children.cend());
884                             }
885                         }
886                     }
887                 }
888                 nodeEntities_.erase(pos);
889                 nodes_.erase(nodes_.cbegin() + index);
890                 lookUp_.erase(oldEntity);
891             }
892         });
893 
894         // Add entities that appeared since last refresh.
895         std::for_each(lastRemoved, lastAdded, [this](Entity newEntity) { AddNode(newEntity); });
896 
897         std::for_each(first, last, [this](Entity entity) {
898             if (SceneNode* sceneNode = GetNode(entity)) {
899                 if (const auto nodeComponent = nodeComponentManager_.Read(entity)) {
900                     if (sceneNode->lastState_.parent != nodeComponent->parent) {
901                         if (SceneNode* oldParent = GetNode(sceneNode->lastState_.parent)) {
902                             oldParent->children_.erase(
903                                 std::remove(oldParent->children_.begin(), oldParent->children_.end(), sceneNode),
904                                 oldParent->children_.cend());
905                         }
906                         sceneNode->lastState_.parent = {};
907                         sceneNode->lastState_.parentChanged = true;
908                         if (SceneNode* newParent = GetNode(nodeComponent->parent)) {
909                             // Set parent / child relationship.
910                             if (std::none_of(newParent->children_.cbegin(), newParent->children_.cend(),
911                                     [sceneNode](const SceneNode* childNode) { return childNode == sceneNode; })) {
912                                 newParent->children_.push_back(sceneNode);
913                             }
914                             sceneNode->lastState_.parent = nodeComponent->parent;
915                         }
916                     }
917                 }
918             }
919         });
920 
921         nodeComponentGenerationId_ = nodeGenerationId;
922         entityGenerationId_ = entityGenerationId;
923     }
924 
InternalNodeUpdate()925     void InternalNodeUpdate()
926     {
927         const uint32_t nodeGenerationId = nodeComponentManager_.GetGenerationCounter();
928         const uint32_t entityGenerationId = entityManager_.GetGenerationCounter();
929         if (nodeGenerationId <= (nodeComponentGenerationId_ + 1U) && entityGenerationId <= (entityGenerationId_ + 1U)) {
930             nodeComponentGenerationId_ = nodeGenerationId;
931             entityGenerationId_ = entityGenerationId;
932         }
933     }
934 
935     // Internally for NodeSystem to skip unneccessary NodeCache::Refresh calls
GetParentNoRefresh(ISceneNode const & node) const936     SceneNode* GetParentNoRefresh(ISceneNode const& node) const
937     {
938         Entity parent;
939         if (ScopedHandle<const NodeComponent> data = nodeComponentManager_.Read(node.GetEntity()); data) {
940             parent = data->parent;
941         }
942 
943         if (EntityUtil::IsValid(parent)) {
944             return GetNode(parent);
945         }
946         return nullptr;
947     }
948 
AddListener(SceneNodeListener & listener)949     void AddListener(SceneNodeListener& listener)
950     {
951         if (Find(listeners_, &listener) != listeners_.end()) {
952             // already added.
953             return;
954         }
955         listeners_.push_back(&listener);
956     }
957 
RemoveListener(SceneNodeListener & listener)958     void RemoveListener(SceneNodeListener& listener)
959     {
960         if (auto it = Find(listeners_, &listener); it != listeners_.end()) {
961             *it = nullptr;
962             return;
963         }
964     }
965 
966 private:
967     vector<Entity> nodeEntities_;
968     vector<unique_ptr<SceneNode>> nodes_;
969     unordered_map<Entity, SceneNode*> lookUp_;
970 
971     uint32_t nodeComponentGenerationId_ = { 0 };
972     uint32_t entityGenerationId_ = { 0 };
973 
974     INameComponentManager& nameComponentManager_;
975     INodeComponentManager& nodeComponentManager_;
976     ITransformComponentManager& transformComponentManager_;
977     IEntityManager& entityManager_;
978 
979     BASE_NS::vector<SceneNodeListener*> listeners_;
980 };
981 
982 // State when traversing node tree.
983 struct NodeSystem::State {
984     SceneNode* node;
985     Math::Mat4X4 parentMatrix;
986     bool parentEnabled;
987 };
988 
SetActive(bool state)989 void NodeSystem::SetActive(bool state)
990 {
991     active_ = state;
992 }
993 
IsActive() const994 bool NodeSystem::IsActive() const
995 {
996     return active_;
997 }
998 
NodeSystem(IEcs & ecs)999 NodeSystem::NodeSystem(IEcs& ecs)
1000     : ecs_(ecs), nameManager_(*(GetManager<INameComponentManager>(ecs))),
1001       nodeManager_(*(GetManager<INodeComponentManager>(ecs))),
1002       transformManager_(*(GetManager<ITransformComponentManager>(ecs))),
1003       localMatrixManager_(*(GetManager<ILocalMatrixComponentManager>(ecs))),
1004       worldMatrixManager_(*(GetManager<IWorldMatrixComponentManager>(ecs))),
1005       prevWorldMatrixManager_(*(GetManager<IPreviousWorldMatrixComponentManager>(ecs))),
1006       cache_(make_unique<NodeCache>(ecs.GetEntityManager(), nameManager_, nodeManager_, transformManager_))
1007 {}
1008 
GetName() const1009 string_view NodeSystem::GetName() const
1010 {
1011     return CORE3D_NS::GetName(this);
1012 }
1013 
GetUid() const1014 Uid NodeSystem::GetUid() const
1015 {
1016     return UID;
1017 }
1018 
GetProperties()1019 IPropertyHandle* NodeSystem::GetProperties()
1020 {
1021     return nullptr;
1022 }
1023 
GetProperties() const1024 const IPropertyHandle* NodeSystem::GetProperties() const
1025 {
1026     return nullptr;
1027 }
1028 
SetProperties(const IPropertyHandle &)1029 void NodeSystem::SetProperties(const IPropertyHandle&) {}
1030 
GetECS() const1031 const IEcs& NodeSystem::GetECS() const
1032 {
1033     return ecs_;
1034 }
1035 
GetRootNode() const1036 ISceneNode& NodeSystem::GetRootNode() const
1037 {
1038     if (auto rootNode = cache_->GetNode(Entity()); rootNode) {
1039         return *rootNode;
1040     }
1041     std::abort();
1042 }
1043 
GetNode(Entity entity) const1044 ISceneNode* NodeSystem::GetNode(Entity entity) const
1045 {
1046     if (EntityUtil::IsValid(entity)) {
1047         // Make sure node cache is valid.
1048         cache_->Refresh();
1049 
1050         return cache_->GetNode(entity);
1051     }
1052     return nullptr;
1053 }
1054 
CreateNode()1055 ISceneNode* NodeSystem::CreateNode()
1056 {
1057     const Entity entity = ecs_.GetEntityManager().Create();
1058 
1059     nodeManager_.Create(entity);
1060     nameManager_.Create(entity);
1061     transformManager_.Create(entity);
1062     localMatrixManager_.Create(entity);
1063     worldMatrixManager_.Create(entity);
1064     cache_->InternalNodeUpdate();
1065     return cache_->AddNode(entity);
1066 }
1067 
CloneNode(const ISceneNode & node,bool recursive)1068 ISceneNode* NodeSystem::CloneNode(const ISceneNode& node, bool recursive)
1069 {
1070     // gather all the entities in the hierarchy
1071     vector<Entity> nodes;
1072     nodes.reserve(nodeManager_.GetComponentCount());
1073     if (recursive) {
1074         GatherNodeEntities(node, nodes);
1075     } else {
1076         nodes.push_back(node.GetEntity());
1077     }
1078 
1079     // clone the hierachy while gathering a map from old to new entities
1080     unordered_map<Entity, Entity> oldToNew;
1081     oldToNew.reserve(nodes.size());
1082     for (const Entity& originalEntity : nodes) {
1083         oldToNew.insert({ originalEntity, ecs_.CloneEntity(originalEntity) });
1084     }
1085     auto update = [](const unordered_map<Entity, Entity>& oldToNew, const Property& property, IPropertyHandle* handle,
1086                       Entity current, size_t entityIdx) {
1087         if (EntityUtil::IsValid(current)) {
1088             if (const auto pos = oldToNew.find(current); pos != oldToNew.end()) {
1089                 reinterpret_cast<Entity*>(reinterpret_cast<uintptr_t>(handle->WLock()) + property.offset)[entityIdx] =
1090                     pos->second;
1091                 handle->WUnlock();
1092             }
1093         }
1094     };
1095     // go through the new entities and update their components to point to the clones instead of originals.
1096     auto managers = ecs_.GetComponentManagers();
1097     for (auto [oldEntity, newEntity] : oldToNew) {
1098         for (auto cm : managers) {
1099             if (auto handle = cm->GetData(newEntity); handle) {
1100                 for (const auto& property : handle->Owner()->MetaData()) {
1101                     if ((property.type == PropertyType::ENTITY_T) || (property.type == PropertyType::ENTITY_ARRAY_T)) {
1102                         const Entity* entities = reinterpret_cast<const Entity*>(
1103                             reinterpret_cast<uintptr_t>(handle->RLock()) + property.offset);
1104                         size_t entityIdx = 0;
1105                         for (auto current : array_view(entities, property.count)) {
1106                             update(oldToNew, property, handle, current, entityIdx);
1107                             ++entityIdx;
1108                         }
1109                         handle->RUnlock();
1110                     }
1111                 }
1112             }
1113         }
1114     }
1115 
1116     return GetNode(oldToNew[nodes.front()]);
1117 }
1118 
DestroyNode(ISceneNode & rootNode)1119 void NodeSystem::DestroyNode(ISceneNode& rootNode)
1120 {
1121     // Make sure node cache is valid.
1122     cache_->Refresh();
1123 
1124     IEntityManager& entityManager = ecs_.GetEntityManager();
1125 
1126     auto* node = static_cast<SceneNode*>(&rootNode);
1127     for (bool done = false; !done && node;) {
1128         if (auto child = node->PopChildNoRefresh(); !child) {
1129             auto* destroy = std::exchange(node, cache_->GetParentNoRefresh(*node));
1130             if (destroy == &rootNode) {
1131                 done = true;
1132                 if (node) {
1133                     node->children_.erase(
1134                         std::remove(node->children_.begin(), node->children_.end(), destroy), node->children_.cend());
1135                     destroy->lastState_.parent = {};
1136                     destroy->lastState_.parentChanged = true;
1137                 }
1138                 // check this is not the root node which cannot be destroyed.
1139                 const auto entity = destroy->GetEntity();
1140                 if (EntityUtil::IsValid(entity)) {
1141                     entityManager.Destroy(entity);
1142                 }
1143             } else {
1144                 entityManager.Destroy(destroy->GetEntity());
1145             }
1146         } else {
1147             node = child;
1148         }
1149     }
1150 }
1151 
AddListener(SceneNodeListener & listener)1152 void NodeSystem::AddListener(SceneNodeListener& listener)
1153 {
1154     cache_->AddListener(listener);
1155 }
1156 
RemoveListener(SceneNodeListener & listener)1157 void NodeSystem::RemoveListener(SceneNodeListener& listener)
1158 {
1159     cache_->RemoveListener(listener);
1160 }
1161 
Initialize()1162 void NodeSystem::Initialize()
1163 {
1164     ComponentQuery::Operation operations[] = {
1165         { localMatrixManager_, ComponentQuery::Operation::Method::OPTIONAL },
1166         { prevWorldMatrixManager_, ComponentQuery::Operation::Method::OPTIONAL },
1167         { worldMatrixManager_, ComponentQuery::Operation::Method::OPTIONAL },
1168     };
1169     CORE_ASSERT(&operations[LOCAL_INDEX - 1U].target == &localMatrixManager_);
1170     CORE_ASSERT(&operations[WORLD_INDEX - 1U].target == &worldMatrixManager_);
1171     CORE_ASSERT(&operations[PREV_WORLD_INDEX - 1U].target == &prevWorldMatrixManager_);
1172     nodeQuery_.SetupQuery(nodeManager_, operations, true);
1173     nodeQuery_.SetEcsListenersEnabled(true);
1174 }
1175 
Update(bool,uint64_t,uint64_t)1176 bool NodeSystem::Update(bool, uint64_t, uint64_t)
1177 {
1178     if (!active_) {
1179         return false;
1180     }
1181 
1182     nodeQuery_.Execute();
1183 
1184     // Cache world matrices from previous frame.
1185     const bool missingPrevWorldMatrix = UpdatePreviousWorldMatrices();
1186 
1187     if (localMatrixGeneration_ == localMatrixManager_.GetGenerationCounter() &&
1188         nodeGeneration_ == nodeManager_.GetGenerationCounter()) {
1189         return false;
1190     }
1191 
1192     // Make sure node cache is valid.
1193     cache_->Refresh();
1194 
1195     vector<ISceneNode*> changedNodes;
1196     changedNodes.reserve(256u); // reserve a chunk to fit a large scene.
1197 
1198     // Find all parent nodes that have their transform updated.
1199     CollectChangedNodes(GetRootNode(), changedNodes);
1200 
1201     // Update world transformations for changed tree branches.
1202     for (const auto node : changedNodes) {
1203         bool parentEnabled = true;
1204         Math::Mat4X4 parentMatrix(1.0f);
1205 
1206         if (const ISceneNode* parent = node->GetParent(); parent) {
1207             // Get parent world matrix.
1208             if (auto row = nodeQuery_.FindResultRow(parent->GetEntity()); row) {
1209                 if (row->IsValidComponentId(WORLD_INDEX)) {
1210                     parentMatrix = worldMatrixManager_.Get(row->components[WORLD_INDEX]).matrix;
1211                 }
1212                 if (auto nodeHandle = nodeManager_.Read(row->components[NODE_INDEX])) {
1213                     parentEnabled = nodeHandle->effectivelyEnabled;
1214                 } else {
1215                     CORE_LOG_W("%" PRIx64 " missing Node", row->entity.id);
1216                 }
1217             }
1218         }
1219 
1220         UpdateTransformations(*node, parentMatrix, parentEnabled);
1221     }
1222 
1223     // Store generation counters.
1224     localMatrixGeneration_ = localMatrixManager_.GetGenerationCounter();
1225     nodeGeneration_ = nodeManager_.GetGenerationCounter();
1226 
1227     if (missingPrevWorldMatrix) {
1228         for (const auto& row : nodeQuery_.GetResults()) {
1229             // Create missing PreviousWorldMatrixComponents and initialize with current world.
1230             if (!row.IsValidComponentId(PREV_WORLD_INDEX) && row.IsValidComponentId(WORLD_INDEX)) {
1231                 prevWorldMatrixManager_.Create(row.entity);
1232                 if (auto dst = prevWorldMatrixManager_.Write(row.entity)) {
1233                     if (auto src = worldMatrixManager_.Read(row.components[WORLD_INDEX])) {
1234                         dst->matrix = src->matrix;
1235                     } else {
1236                         CORE_LOG_W("%" PRIx64 " missing WorldMatrix", row.entity.id);
1237                     }
1238                 } else {
1239                     CORE_LOG_W("%" PRIx64 " missing PreviousWorldMatrix", row.entity.id);
1240                 }
1241             }
1242         }
1243     }
1244 
1245     return true;
1246 }
1247 
Uninitialize()1248 void NodeSystem::Uninitialize()
1249 {
1250     cache_->Reset();
1251     nodeQuery_.SetEcsListenersEnabled(false);
1252 }
1253 
CollectChangedNodes(ISceneNode & node,vector<ISceneNode * > & result)1254 void NodeSystem::CollectChangedNodes(ISceneNode& node, vector<ISceneNode*>& result)
1255 {
1256     auto& sceneNode = (const SceneNode&)(node);
1257     auto& lastState = sceneNode.lastState_;
1258 
1259     if (auto row = nodeQuery_.FindResultRow(node.GetEntity()); row) {
1260         // If local matrix component has changed, the sub-tree needs to be recalculated.
1261         if (row->IsValidComponentId(LOCAL_INDEX)) {
1262             const uint32_t currentGeneration = localMatrixManager_.GetComponentGeneration(row->components[LOCAL_INDEX]);
1263             if (lastState.localMatrixGeneration != currentGeneration) {
1264                 result.push_back(&node);
1265                 return;
1266             }
1267         }
1268 
1269         // If node enabled state or parent component has changed, the sub-tree needs to be recalculated.
1270         if (const auto& nodeComponent = nodeManager_.Read(row->components[NODE_INDEX])) {
1271             const bool parentChanged = (lastState.parent != nodeComponent->parent) || lastState.parentChanged;
1272             const bool enabledChanged = lastState.enabled != nodeComponent->enabled;
1273             if (parentChanged || enabledChanged) {
1274                 result.push_back(&node);
1275                 return;
1276             }
1277         } else {
1278             CORE_LOG_W("%" PRIx64 " missing Node", row->entity.id);
1279         }
1280     }
1281 
1282     for (auto* const child : node.GetChildren()) {
1283         if (child) {
1284             CollectChangedNodes(*child, result);
1285         }
1286     }
1287 }
1288 
1289 struct NodeSystem::NodeInfo {
1290     Entity parent;
1291     bool isEffectivelyEnabled;
1292     bool effectivelyEnabledChanged;
1293 };
1294 
ProcessNode(SceneNode * node,const bool parentEnabled,const ComponentQuery::ResultRow * row)1295 NodeSystem::NodeInfo NodeSystem::ProcessNode(
1296     SceneNode* node, const bool parentEnabled, const ComponentQuery::ResultRow* row)
1297 {
1298     NodeInfo info;
1299     info.isEffectivelyEnabled = parentEnabled;
1300     info.effectivelyEnabledChanged = false;
1301 
1302     IPropertyHandle* handle = nodeManager_.GetData(row->components[NODE_INDEX]);
1303     auto nc = ScopedHandle<const NodeComponent>(handle);
1304     info.parent = nc->parent;
1305     const bool nodeEnabled = nc->enabled;
1306     // Update effectively enabled status if it has changed (e.g. due to parent enabled state changes).
1307     info.isEffectivelyEnabled = info.isEffectivelyEnabled && nodeEnabled;
1308     if (nc->effectivelyEnabled != info.isEffectivelyEnabled) {
1309         ScopedHandle<NodeComponent>(handle)->effectivelyEnabled = info.isEffectivelyEnabled;
1310         cache_->InternalNodeUpdate();
1311         info.effectivelyEnabledChanged = true;
1312     }
1313     node->lastState_.enabled = nodeEnabled;
1314 
1315     return info;
1316 }
1317 
UpdateTransformations(ISceneNode & node,Math::Mat4X4 const & matrix,bool enabled)1318 void NodeSystem::UpdateTransformations(ISceneNode& node, Math::Mat4X4 const& matrix, bool enabled)
1319 {
1320     BASE_NS::vector<State> stack;
1321     stack.reserve(nodeManager_.GetComponentCount());
1322     stack.push_back(State { static_cast<SceneNode*>(&node), matrix, enabled });
1323     while (!stack.empty()) {
1324         auto state = stack.back();
1325         stack.pop_back();
1326 
1327         auto row = nodeQuery_.FindResultRow(state.node->GetEntity());
1328         if (!row) {
1329             continue;
1330         }
1331         const auto nodeInfo = ProcessNode(state.node, state.parentEnabled, row);
1332 
1333         Math::Mat4X4& pm = state.parentMatrix;
1334 
1335         if (nodeInfo.isEffectivelyEnabled && row->IsValidComponentId(LOCAL_INDEX)) {
1336             if (auto local = localMatrixManager_.Read(row->components[LOCAL_INDEX])) {
1337                 pm = pm * local->matrix;
1338             } else {
1339                 CORE_LOG_W("%" PRIx64 " missing LocalWorldMatrix", row->entity.id);
1340             }
1341 
1342             if (row->IsValidComponentId(WORLD_INDEX)) {
1343                 if (auto worldMatrixHandle = worldMatrixManager_.Write(row->components[WORLD_INDEX])) {
1344                     worldMatrixHandle->matrix = pm;
1345                 } else {
1346                     CORE_LOG_W("%" PRIx64 " missing WorldMatrix", row->entity.id);
1347                 }
1348             } else {
1349                 worldMatrixManager_.Set(row->entity, { pm });
1350             }
1351 
1352             // Save the values that were used to calculate current world matrix.
1353             state.node->lastState_.localMatrixGeneration =
1354                 localMatrixManager_.GetComponentGeneration(row->components[LOCAL_INDEX]);
1355             state.node->lastState_.parent = nodeInfo.parent;
1356         }
1357         if (nodeInfo.isEffectivelyEnabled || nodeInfo.effectivelyEnabledChanged) {
1358             for (auto* child : state.node->GetChildren()) {
1359                 if (child) {
1360                     stack.push_back(State { static_cast<SceneNode*>(child), pm, nodeInfo.isEffectivelyEnabled });
1361                 }
1362             }
1363         }
1364     }
1365 }
1366 
GatherNodeEntities(const ISceneNode & node,vector<Entity> & entities) const1367 void NodeSystem::GatherNodeEntities(const ISceneNode& node, vector<Entity>& entities) const
1368 {
1369     entities.push_back(node.GetEntity());
1370     for (const ISceneNode* child : node.GetChildren()) {
1371         if (child) {
1372             GatherNodeEntities(*child, entities);
1373         }
1374     }
1375 }
1376 
UpdatePreviousWorldMatrices()1377 bool NodeSystem::UpdatePreviousWorldMatrices()
1378 {
1379     bool missingPrevWorldMatrix = false;
1380     if (worldMatrixGeneration_ != worldMatrixManager_.GetGenerationCounter()) {
1381         worldMatrixGeneration_ = worldMatrixManager_.GetGenerationCounter();
1382 
1383         for (const auto& row : nodeQuery_.GetResults()) {
1384             const bool hasPrev = row.IsValidComponentId(PREV_WORLD_INDEX);
1385             if (hasPrev && row.IsValidComponentId(WORLD_INDEX)) {
1386                 if (auto dst = prevWorldMatrixManager_.Write(row.components[PREV_WORLD_INDEX])) {
1387                     if (auto src = worldMatrixManager_.Read(row.components[WORLD_INDEX])) {
1388                         dst->matrix = src->matrix;
1389                     } else {
1390                         CORE_LOG_W("%" PRIx64 " missing WorldMatrix", row.entity.id);
1391                     }
1392                 } else {
1393                     CORE_LOG_W("%" PRIx64 " missing PreviousWorldMatrix", row.entity.id);
1394                 }
1395             } else if (!hasPrev) {
1396                 missingPrevWorldMatrix = true;
1397             }
1398         }
1399     }
1400     return missingPrevWorldMatrix;
1401 }
1402 
INodeSystemInstance(IEcs & ecs)1403 ISystem* INodeSystemInstance(IEcs& ecs)
1404 {
1405     return new NodeSystem(ecs);
1406 }
INodeSystemDestroy(ISystem * instance)1407 void INodeSystemDestroy(ISystem* instance)
1408 {
1409     delete static_cast<NodeSystem*>(instance);
1410 }
1411 
1412 CORE3D_END_NAMESPACE()
1413