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