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