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