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