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