Line data Source code
1 : /**
2 : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLNode.h"
25 :
26 : #include "XLInputDispatcher.h"
27 : #include "XLInputListener.h"
28 : #include "XLComponent.h"
29 : #include "XLScene.h"
30 : #include "XLDirector.h"
31 : #include "XLScheduler.h"
32 : #include "XLActionManager.h"
33 : #include "XLFrameInfo.h"
34 :
35 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
36 :
37 147 : void ActionStorage::addAction(Rc<Action> &&a) {
38 147 : actionToStart.emplace_back(move(a));
39 147 : }
40 :
41 21 : void ActionStorage::removeAction(Action *a) {
42 21 : auto it = std::find(actionToStart.begin(), actionToStart.end(), a);
43 21 : if (it != actionToStart.end()) {
44 21 : actionToStart.erase(it);
45 : }
46 21 : }
47 :
48 21 : void ActionStorage::removeAllActions() {
49 21 : actionToStart.clear();
50 21 : }
51 :
52 21 : void ActionStorage::removeActionByTag(uint32_t tag) {
53 21 : auto it = actionToStart.begin();
54 21 : while (it != actionToStart.end()) {
55 21 : if (it->get()->getTag() == tag) {
56 21 : actionToStart.erase(it);
57 21 : return;
58 : }
59 0 : ++ it;
60 : }
61 : }
62 :
63 21 : void ActionStorage::removeAllActionsByTag(uint32_t tag) {
64 21 : auto it = actionToStart.begin();
65 42 : while (it != actionToStart.end()) {
66 21 : if (it->get()) {
67 21 : if (it->get()->getTag() == tag) {
68 21 : it = actionToStart.erase(it);
69 21 : continue;
70 : }
71 : }
72 0 : ++ it;
73 : }
74 21 : }
75 :
76 21 : Action *ActionStorage::getActionByTag(uint32_t tag) {
77 21 : for (auto &it : actionToStart) {
78 21 : if (it->getTag() == tag) {
79 21 : return it;
80 : }
81 : }
82 0 : return nullptr;
83 : }
84 :
85 216 : String MaterialInfo::description() const {
86 216 : StringStream stream;
87 :
88 216 : stream << "{" << images[0] << "," << images[1] << "," << images[2] << "," << images[3] << "},"
89 216 : << "{" << samplers[0] << "," << samplers[1] << "," << samplers[2] << "," << samplers[3] << "},"
90 216 : << "{" << colorModes[0].toInt() << "," << colorModes[1].toInt() << "," << colorModes[2].toInt() << "," << colorModes[3].toInt() << "},"
91 216 : << "," << pipeline.description();
92 :
93 432 : return stream.str();
94 216 : }
95 :
96 27 : bool MaterialInfo::hasImage(uint64_t id) const {
97 27 : for (auto &it : images) {
98 27 : if (it == id) {
99 27 : return true;
100 : }
101 : }
102 0 : return false;
103 : }
104 :
105 105 : bool Node::isParent(Node *parent, Node *node) {
106 105 : if (!node) {
107 0 : return false;
108 : }
109 105 : auto p = node->getParent();
110 315 : while (p) {
111 315 : if (p == parent) {
112 105 : return true;
113 : }
114 210 : p = p->getParent();
115 : }
116 0 : return false;
117 : }
118 :
119 42 : Mat4 Node::getChainNodeToParentTransform(Node *parent, Node *node, bool withParent) {
120 42 : if (!isParent(parent, node)) {
121 0 : return Mat4::IDENTITY;
122 : }
123 :
124 42 : Mat4 ret = node->getNodeToParentTransform();
125 42 : auto p = node->getParent();
126 126 : for (; p != parent; p = p->getParent()) {
127 84 : ret = ret * p->getNodeToParentTransform();
128 : }
129 42 : if (withParent && p == parent) {
130 21 : ret = ret * p->getNodeToParentTransform();
131 : }
132 42 : return ret;
133 : }
134 :
135 42 : Mat4 Node::getChainParentToNodeTransform(Node *parent, Node *node, bool withParent) {
136 42 : if (!isParent(parent, node)) {
137 0 : return Mat4::IDENTITY;
138 : }
139 :
140 42 : Mat4 ret = node->getParentToNodeTransform();
141 42 : auto p = node->getParent();
142 126 : for (; p != parent; p = p->getParent()) {
143 84 : ret = p->getParentToNodeTransform() * ret;
144 : }
145 42 : if (withParent && p == parent) {
146 21 : ret = p->getParentToNodeTransform() * ret;
147 : }
148 42 : return ret;
149 : }
150 :
151 86291 : Node::Node() { }
152 :
153 86582 : Node::~Node() {
154 139593 : for (auto &child : _children) {
155 53302 : child->_parent = nullptr;
156 : }
157 :
158 : // stopAllActions();
159 :
160 86291 : XLASSERT(!_running, "Node still marked as running on node destruction! Was base class onExit() called in derived class onExit() implementations?");
161 86582 : }
162 :
163 86291 : bool Node::init() {
164 86291 : return true;
165 : }
166 :
167 90671 : void Node::setLocalZOrder(ZOrder z) {
168 90671 : if (_zOrder == z) {
169 83075 : return;
170 : }
171 :
172 7596 : _zOrder = z;
173 7596 : if (_parent) {
174 1523 : _parent->reorderChild(this, z);
175 : }
176 : }
177 :
178 210 : void Node::setScale(float scale) {
179 210 : if (_scale.x == scale && _scale.x == scale && _scale.x == scale) {
180 189 : return;
181 : }
182 :
183 21 : _scale.x = _scale.y = _scale.z = scale;
184 21 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
185 : }
186 :
187 21 : void Node::setScale(const Vec2 &scale) {
188 21 : if (_scale.x == scale.x && _scale.y == scale.y) {
189 0 : return;
190 : }
191 :
192 21 : _scale.x = scale.x;
193 21 : _scale.y = scale.y;
194 21 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
195 : }
196 :
197 589 : void Node::setScale(const Vec3 &scale) {
198 589 : if (_scale == scale) {
199 152 : return;
200 : }
201 :
202 437 : _scale = scale;
203 437 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
204 : }
205 :
206 6731 : void Node::setScaleX(float scaleX) {
207 6731 : if (_scale.x == scaleX) {
208 0 : return;
209 : }
210 :
211 6731 : _scale.x = scaleX;
212 6731 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
213 : }
214 :
215 6731 : void Node::setScaleY(float scaleY) {
216 6731 : if (_scale.y == scaleY) {
217 0 : return;
218 : }
219 :
220 6731 : _scale.y = scaleY;
221 6731 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
222 : }
223 :
224 21 : void Node::setScaleZ(float scaleZ) {
225 21 : if (_scale.z == scaleZ) {
226 0 : return;
227 : }
228 :
229 21 : _scale.z = scaleZ;
230 21 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
231 : }
232 :
233 119405 : void Node::setPosition(const Vec2 &position) {
234 119405 : if (_position.x == position.x && _position.y == position.y) {
235 33111 : return;
236 : }
237 :
238 86294 : _position.x = position.x;
239 86294 : _position.y = position.y;
240 86294 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
241 : }
242 :
243 8853 : void Node::setPosition(const Vec3 &position) {
244 8853 : if (_position == position) {
245 881 : return;
246 : }
247 :
248 7972 : _position = position;
249 7972 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
250 : }
251 :
252 109 : void Node::setPositionX(float value) {
253 109 : if (_position.x == value) {
254 109 : return;
255 : }
256 :
257 0 : _position.x = value;
258 0 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
259 : }
260 :
261 768 : void Node::setPositionY(float value) {
262 768 : if (_position.y == value) {
263 172 : return;
264 : }
265 :
266 596 : _position.y = value;
267 596 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
268 : }
269 :
270 1291 : void Node::setPositionZ(float value) {
271 1291 : if (_position.z == value) {
272 21 : return;
273 : }
274 :
275 1270 : _position.z = value;
276 1270 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
277 : }
278 :
279 63 : void Node::setSkewX(float skewX) {
280 63 : if (_skew.x == skewX) {
281 21 : return;
282 : }
283 :
284 42 : _skew.x = skewX;
285 42 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
286 : }
287 :
288 63 : void Node::setSkewY(float skewY) {
289 63 : if (_skew.y == skewY) {
290 21 : return;
291 : }
292 :
293 42 : _skew.y = skewY;
294 42 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
295 : }
296 :
297 110959 : void Node::setAnchorPoint(const Vec2 &point) {
298 110959 : if (point == _anchorPoint) {
299 32135 : return;
300 : }
301 :
302 78824 : _anchorPoint = point;
303 78824 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
304 : }
305 :
306 141553 : void Node::setContentSize(const Size2 &size) {
307 141553 : if (size == _contentSize) {
308 37049 : return;
309 : }
310 :
311 104504 : _contentSize = size;
312 104504 : _transformInverseDirty = _transformCacheDirty = _transformDirty = _contentSizeDirty = true;
313 : }
314 :
315 64924 : void Node::setVisible(bool visible) {
316 64924 : if (visible == _visible) {
317 55899 : return;
318 : }
319 9025 : _visible = visible;
320 9025 : if (_visible) {
321 813 : _contentSizeDirty = _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
322 : }
323 : }
324 :
325 6773 : void Node::setRotation(float rotation) {
326 6773 : if (_rotation.z == rotation && _rotation.x == 0 && _rotation.y == 0) {
327 210 : return;
328 : }
329 :
330 6563 : _rotation = Vec3(0.0f, 0.0f, rotation);
331 6563 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
332 6563 : _rotationQuat = Quaternion(_rotation);
333 : }
334 :
335 21 : void Node::setRotation(const Vec3 &rotation) {
336 21 : if (_rotation == rotation) {
337 0 : return;
338 : }
339 :
340 21 : _rotation = rotation;
341 21 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
342 21 : _rotationQuat = Quaternion(_rotation);
343 : }
344 :
345 21 : void Node::setRotation(const Quaternion &quat) {
346 21 : if (_rotationQuat == quat) {
347 0 : return;
348 : }
349 :
350 21 : _rotationQuat = quat;
351 21 : _rotation = _rotationQuat.toEulerAngles();
352 21 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
353 : }
354 :
355 79954 : void Node::addChildNode(Node *child) {
356 79954 : addChildNode(child, child->_zOrder, child->_tag);
357 79954 : }
358 :
359 6031 : void Node::addChildNode(Node *child, ZOrder localZOrder) {
360 6031 : addChildNode(child, localZOrder, child->_tag);
361 6031 : }
362 :
363 86258 : void Node::addChildNode(Node *child, ZOrder localZOrder, uint64_t tag) {
364 86258 : XLASSERT( child != nullptr, "Argument must be non-nil");
365 86258 : XLASSERT( child->_parent == nullptr, "child already added. It can't be added again");
366 :
367 : if constexpr (config::NodePreallocateChilds > 1) {
368 86258 : if (_children.empty()) {
369 41497 : _children.reserve(config::NodePreallocateChilds);
370 : }
371 : }
372 :
373 86258 : _reorderChildDirty = true;
374 86258 : _children.push_back(child);
375 86258 : child->setLocalZOrder(localZOrder);
376 86258 : if (tag != InvalidTag) {
377 35415 : child->setTag(tag);
378 : }
379 86258 : child->setParent(this);
380 :
381 86258 : if (_running) {
382 36575 : child->onEnter(_scene);
383 : }
384 :
385 86258 : if (_cascadeColorEnabled) {
386 63 : updateCascadeColor();
387 : }
388 :
389 86258 : if (_cascadeOpacityEnabled) {
390 86258 : updateCascadeOpacity();
391 : }
392 86258 : }
393 :
394 42 : Node* Node::getChildByTag(uint64_t tag) const {
395 42 : XLASSERT( tag != InvalidTag, "Invalid tag");
396 84 : for (const auto &child : _children) {
397 84 : if (child && child->_tag == tag) {
398 42 : return child;
399 : }
400 : }
401 0 : return nullptr;
402 : }
403 :
404 119214 : void Node::setParent(Node *parent) {
405 119214 : if (parent == _parent) {
406 0 : return;
407 : }
408 119214 : _parent = parent;
409 119214 : _transformInverseDirty = _transformCacheDirty = _transformDirty = true;
410 : }
411 :
412 32767 : void Node::removeFromParent(bool cleanup) {
413 32767 : if (_parent != nullptr) {
414 32767 : _parent->removeChild(this, cleanup);
415 : }
416 32767 : }
417 :
418 32788 : void Node::removeChild(Node *child, bool cleanup) {
419 : // explicit nil handling
420 32788 : if (_children.empty()) {
421 0 : return;
422 : }
423 :
424 32788 : auto it = std::find(_children.begin(), _children.end(), child);
425 32788 : if (it != _children.end()) {
426 32788 : if (_running) {
427 32641 : child->onExit();
428 : }
429 :
430 32788 : if (cleanup) {
431 32788 : child->cleanup();
432 : }
433 :
434 : // set parent nil at the end
435 32788 : child->setParent(nullptr);
436 32788 : _children.erase(it);
437 : }
438 : }
439 :
440 21 : void Node::removeChildByTag(uint64_t tag, bool cleanup) {
441 21 : XLASSERT( tag != InvalidTag, "Invalid tag");
442 :
443 21 : Node *child = this->getChildByTag(tag);
444 21 : if (child == nullptr) {
445 0 : log::warn("Node", "removeChildByTag(tag = ", tag, "): child not found!");
446 : } else {
447 21 : this->removeChild(child, cleanup);
448 : }
449 21 : }
450 :
451 63 : void Node::removeAllChildren(bool cleanup) {
452 231 : for (const auto &child : _children) {
453 168 : if (_running) {
454 168 : child->onExit();
455 : }
456 :
457 168 : if (cleanup) {
458 168 : child->cleanup();
459 : }
460 : // set parent nil at the end
461 168 : child->setParent(nullptr);
462 : }
463 :
464 63 : _children.clear();
465 63 : }
466 :
467 1523 : void Node::reorderChild(Node * child, ZOrder localZOrder) {
468 1523 : XLASSERT( child != nullptr, "Child must be non-nil");
469 1523 : _reorderChildDirty = true;
470 1523 : child->setLocalZOrder(localZOrder);
471 1523 : }
472 :
473 264137 : void Node::sortAllChildren() {
474 264137 : if (_reorderChildDirty) {
475 40944 : std::sort(std::begin(_children), std::end(_children), [&] (const Node *l, const Node *r) {
476 270630 : return l->getLocalZOrder() < r->getLocalZOrder();
477 : });
478 40944 : onReorderChildDirty();
479 40944 : _reorderChildDirty = false;
480 : }
481 264137 : }
482 :
483 5250 : void Node::runActionObject(Action *action) {
484 5250 : XLASSERT( action != nullptr, "Argument must be non-nil");
485 :
486 5250 : if (_actionManager) {
487 5103 : _actionManager->addAction(action, this, !_running);
488 : } else {
489 147 : if (!_actionStorage) {
490 84 : _actionStorage = Rc<ActionStorage>::alloc();
491 : }
492 :
493 147 : _actionStorage->addAction(action);
494 : }
495 5250 : }
496 :
497 2124 : void Node::runActionObject(Action *action, uint32_t tag) {
498 2124 : if (action) {
499 2124 : action->setTag(tag);
500 : }
501 2124 : runActionObject(action);
502 2124 : }
503 :
504 69667 : void Node::stopAllActions() {
505 69667 : if (_actionManager) {
506 69625 : _actionManager->removeAllActionsFromTarget(this);
507 42 : } else if (_actionStorage) {
508 21 : _actionStorage->removeAllActions();
509 : }
510 69667 : }
511 :
512 42 : void Node::stopAction(Action *action) {
513 42 : if (_actionManager) {
514 21 : _actionManager->removeAction(action);
515 21 : } else if (_actionStorage) {
516 21 : _actionStorage->removeAction(action);
517 : }
518 42 : }
519 :
520 2520 : void Node::stopActionByTag(uint32_t tag) {
521 2520 : XLASSERT(tag != Action::INVALID_TAG, "Invalid tag");
522 2520 : if (_actionManager) {
523 2499 : _actionManager->removeActionByTag(tag, this);
524 21 : } else if (_actionStorage) {
525 21 : _actionStorage->removeActionByTag(tag);
526 : }
527 2520 : }
528 :
529 1017 : void Node::stopAllActionsByTag(uint32_t tag) {
530 1017 : XLASSERT(tag != Action::INVALID_TAG, "Invalid tag");
531 1017 : if (_actionManager) {
532 996 : _actionManager->removeAllActionsByTag(tag, this);
533 21 : } else if (_actionStorage) {
534 21 : _actionStorage->removeAllActionsByTag(tag);
535 : }
536 1017 : }
537 :
538 1527 : Action* Node::getActionByTag(uint32_t tag) {
539 1527 : XLASSERT(tag != Action::INVALID_TAG, "Invalid tag");
540 1527 : if (_actionManager) {
541 1506 : return _actionManager->getActionByTag(tag, this);
542 21 : } else if (_actionStorage) {
543 21 : return _actionStorage->getActionByTag(tag);
544 : }
545 0 : return nullptr;
546 : }
547 :
548 42 : size_t Node::getNumberOfRunningActions() const {
549 42 : if (_actionManager) {
550 21 : return _actionManager->getNumberOfRunningActionsInTarget(this);
551 21 : } else if (_actionStorage) {
552 21 : return _actionStorage->actionToStart.size();
553 : }
554 0 : return 0;
555 : }
556 :
557 70557 : void Node::setTag(uint64_t tag) {
558 70557 : _tag = tag;
559 70557 : }
560 :
561 5695 : bool Node::addComponentItem(Component *com) {
562 5695 : XLASSERT(com != nullptr, "Argument must be non-nil");
563 5695 : XLASSERT(com->getOwner() == nullptr, "Component already added. It can't be added again");
564 :
565 5695 : _components.push_back(com);
566 5695 : com->onAdded(this);
567 5695 : if (this->isRunning()) {
568 0 : com->onEnter(_scene);
569 : }
570 :
571 5695 : return true;
572 : }
573 :
574 21 : bool Node::removeComponent(Component *com) {
575 21 : if (_components.empty()) {
576 0 : return false;
577 : }
578 :
579 21 : for (auto iter = _components.begin(); iter != _components.end(); ++iter) {
580 21 : if ((*iter) == com) {
581 21 : if (this->isRunning()) {
582 0 : com->onExit();
583 : }
584 21 : com->onRemoved();
585 21 : _components.erase(iter);
586 21 : return true;
587 : }
588 : }
589 0 : return false;
590 : }
591 :
592 21 : bool Node::removeComponentByTag(uint64_t tag) {
593 21 : if (_components.empty()) {
594 0 : return false;
595 : }
596 :
597 21 : for (auto iter = _components.begin(); iter != _components.end(); ++iter) {
598 21 : if ((*iter)->getFrameTag() == tag) {
599 21 : auto com = (*iter);
600 21 : if (this->isRunning()) {
601 0 : com->onExit();
602 : }
603 21 : com->onRemoved();
604 21 : _components.erase(iter);
605 21 : return true;
606 21 : }
607 : }
608 0 : return false;
609 : }
610 :
611 21 : bool Node::removeAllComponentByTag(uint64_t tag) {
612 21 : if (_components.empty()) {
613 0 : return false;
614 : }
615 :
616 21 : auto iter = _components.begin();
617 63 : while (iter != _components.end()) {
618 42 : if ((*iter)->getFrameTag() == tag) {
619 42 : auto com = (*iter);
620 42 : if (this->isRunning()) {
621 0 : com->onExit();
622 : }
623 42 : com->onRemoved();
624 42 : iter = _components.erase(iter);
625 42 : } else {
626 0 : ++ iter;
627 : }
628 : }
629 21 : return false;
630 : }
631 :
632 68607 : void Node::removeAllComponents() {
633 70203 : for (auto iter : _components) {
634 1596 : if (this->isRunning()) {
635 0 : iter->onExit();
636 : }
637 1596 : iter->onRemoved();
638 1596 : }
639 :
640 68607 : _components.clear();
641 68607 : }
642 :
643 877 : bool Node::addInputListenerItem(InputListener *input) {
644 877 : XLASSERT(input != nullptr, "Argument must be non-nil");
645 877 : XLASSERT(input->getOwner() == nullptr, "Component already added. It can't be added again");
646 :
647 877 : input->setOwner(this);
648 877 : _inputEvents.push_back(input);
649 877 : if (this->isRunning()) {
650 0 : input->onEnter(_scene);
651 : }
652 :
653 877 : return true;
654 : }
655 :
656 21 : bool Node::removeInputListener(InputListener *input) {
657 21 : if (_inputEvents.empty()) {
658 0 : return false;
659 : }
660 :
661 21 : for (auto iter = _inputEvents.begin(); iter != _inputEvents.end(); ++iter) {
662 21 : if ((*iter) == input) {
663 21 : if (this->isRunning()) {
664 21 : input->onExit();
665 : }
666 21 : input->setOwner(nullptr);
667 21 : _inputEvents.erase(iter);
668 21 : return true;
669 : }
670 : }
671 0 : return false;
672 : }
673 :
674 86279 : void Node::onEnter(Scene *scene) {
675 86279 : _scene = scene;
676 86279 : _director = scene->getDirector();
677 :
678 86279 : if (!_frameContext && _parent) {
679 86237 : _frameContext = _parent->getFrameContext();
680 42 : } else if (_frameContext) {
681 21 : _frameContext->onEnter(scene);
682 : }
683 :
684 86279 : if (_scheduler != _director->getScheduler()) {
685 86279 : if (_scheduler) {
686 0 : _scheduler->unschedule(this);
687 : }
688 86279 : _scheduler = _director->getScheduler();
689 : }
690 :
691 86279 : if (_actionManager != _director->getActionManager()) {
692 86279 : if (_actionManager) {
693 0 : _actionManager->removeAllActionsFromTarget(this);
694 : }
695 86279 : _actionManager = _director->getActionManager();
696 :
697 86279 : if (_actionStorage) {
698 147 : for (auto &it : _actionStorage->actionToStart) {
699 63 : runActionObject(it);
700 : }
701 84 : _actionStorage = nullptr;
702 : }
703 : }
704 :
705 86279 : if (_onEnterCallback) {
706 21 : _onEnterCallback(scene);
707 : }
708 :
709 91869 : for (auto &it : _components) {
710 5590 : it->onEnter(scene);
711 : }
712 :
713 87156 : for (auto &it : _inputEvents) {
714 877 : it->onEnter(scene);
715 : }
716 :
717 135962 : for (auto &child : _children) {
718 49683 : child->onEnter(scene);
719 : }
720 :
721 86279 : if (_scheduled) {
722 84 : _scheduler->scheduleUpdate(this, 0, _paused);
723 : }
724 :
725 86279 : _running = true;
726 86279 : this->resume();
727 86279 : }
728 :
729 86279 : void Node::onExit() {
730 : // In reverse order from onEnter()
731 :
732 86279 : this->pause();
733 86279 : _running = false;
734 :
735 86279 : if (_scheduled) {
736 105 : _scheduler->unschedule(this);
737 105 : _scheduled = true; // -re-enable after restart;
738 : }
739 :
740 139728 : for (auto &child : _children) {
741 53449 : child->onExit();
742 : }
743 :
744 87135 : for (auto &it : _inputEvents) {
745 856 : it->onExit();
746 : }
747 :
748 91869 : for (auto &it : _components) {
749 5590 : it->onExit();
750 : }
751 :
752 86279 : if (_onExitCallback) {
753 21 : _onExitCallback();
754 : }
755 :
756 86279 : if (_frameContext && _parent && _parent->getFrameContext() != _frameContext) {
757 21 : _frameContext->onExit();
758 : } else {
759 86258 : _frameContext = nullptr;
760 : }
761 :
762 : // prevent node destruction until update is ended
763 86279 : _director->autorelease(this);
764 :
765 86279 : _scene = nullptr;
766 86279 : _director = nullptr;
767 86279 : }
768 :
769 92401 : void Node::onContentSizeDirty() {
770 92401 : if (_onContentSizeDirtyCallback) {
771 3179 : _onContentSizeDirtyCallback();
772 : }
773 :
774 102144 : for (auto &it : _components) {
775 9743 : it->onContentSizeDirty();
776 : }
777 92401 : }
778 :
779 103652 : void Node::onTransformDirty(const Mat4 &parentTransform) {
780 103652 : if (_onTransformDirtyCallback) {
781 1191 : _onTransformDirtyCallback(parentTransform);
782 : }
783 :
784 112935 : for (auto &it : _components) {
785 9283 : it->onTransformDirty(parentTransform);
786 : }
787 103652 : }
788 :
789 146917 : void Node::onGlobalTransformDirty(const Mat4 &parentTransform) {
790 146917 : Vec3 scale;
791 146917 : parentTransform.decompose(&scale, nullptr, nullptr);
792 :
793 146917 : if (_scale.x != 1.f) { scale.x *= _scale.x; }
794 146917 : if (_scale.y != 1.f) { scale.y *= _scale.y; }
795 146917 : if (_scale.z != 1.f) { scale.z *= _scale.z; }
796 :
797 146917 : auto density = std::min(std::min(scale.x, scale.y), scale.z);
798 146917 : if (density != _inputDensity) {
799 3208 : for (auto &it : _inputEvents) {
800 126 : it->setDensity(density);
801 : }
802 3082 : _inputDensity = density;
803 : }
804 146917 : }
805 :
806 40944 : void Node::onReorderChildDirty() {
807 40944 : if (_onReorderChildDirtyCallback) {
808 27 : _onReorderChildDirtyCallback();
809 : }
810 :
811 45815 : for (auto &it : _components) {
812 4871 : it->onReorderChildDirty();
813 : }
814 40944 : }
815 :
816 68586 : void Node::cleanup() {
817 68586 : if (_actionManager) {
818 68586 : this->stopAllActions();
819 : }
820 68586 : if (_scheduler) {
821 68586 : this->unscheduleUpdate();
822 : }
823 :
824 104216 : for (auto &child : _children) {
825 35630 : child->cleanup();
826 : }
827 :
828 68586 : this->removeAllComponents();
829 :
830 68859 : for (auto &it : _inputEvents) {
831 273 : if (this->isRunning()) {
832 0 : it->onExit();
833 : }
834 273 : it->setOwner(nullptr);
835 : }
836 68586 : _inputEvents.clear();
837 68586 : }
838 :
839 21 : Rect Node::getBoundingBox() const {
840 21 : Rect rect(0, 0, _contentSize.width, _contentSize.height);
841 42 : return TransformRect(rect, getNodeToParentTransform());
842 : }
843 :
844 86300 : void Node::resume() {
845 86300 : if (_paused) {
846 21 : _paused = false;
847 21 : if (_running && _scheduled) {
848 0 : _scheduler->resume(this);
849 0 : _actionManager->resumeTarget(this);
850 : }
851 : }
852 86300 : }
853 :
854 86300 : void Node::pause() {
855 86300 : if (!_paused) {
856 86300 : if (_running && _scheduled) {
857 105 : _actionManager->pauseTarget(this);
858 105 : _scheduler->pause(this);
859 : }
860 86300 : _paused = true;
861 : }
862 86300 : }
863 :
864 63077 : void Node::update(const UpdateTime &time) {
865 :
866 63077 : }
867 :
868 199573 : const Mat4& Node::getNodeToParentTransform() const {
869 199573 : if (_transformCacheDirty) {
870 : // Translate values
871 103778 : float x = _position.x;
872 103778 : float y = _position.y;
873 103778 : float z = _position.z;
874 :
875 103778 : bool needsSkewMatrix = (_skew.x || _skew.y);
876 :
877 103778 : Vec2 anchorPointInPoints(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
878 103778 : Vec2 anchorPoint(anchorPointInPoints.x * _scale.x, anchorPointInPoints.y * _scale.y);
879 :
880 : // caculate real position
881 103778 : if (!needsSkewMatrix && anchorPointInPoints != Vec2::ZERO) {
882 86447 : x += -anchorPoint.x;
883 86447 : y += -anchorPoint.y;
884 : }
885 :
886 : // Build Transform Matrix = translation * rotation * scale
887 103778 : Mat4 translation;
888 : //move to anchor point first, then rotate
889 103778 : Mat4::createTranslation(x + anchorPoint.x, y + anchorPoint.y, z, &translation);
890 :
891 103778 : Mat4::createRotation(_rotationQuat, &_transform);
892 :
893 103778 : _transform = translation * _transform;
894 : //move by (-anchorPoint.x, -anchorPoint.y, 0) after rotation
895 103778 : _transform.translate(-anchorPoint.x, -anchorPoint.y, 0);
896 :
897 103778 : if (_scale.x != 1.f) {
898 7015 : _transform.m[0] *= _scale.x, _transform.m[1] *= _scale.x, _transform.m[2] *= _scale.x;
899 : }
900 103778 : if (_scale.y != 1.f) {
901 7152 : _transform.m[4] *= _scale.y, _transform.m[5] *= _scale.y, _transform.m[6] *= _scale.y;
902 : }
903 103778 : if (_scale.z != 1.f) {
904 442 : _transform.m[8] *= _scale.z, _transform.m[9] *= _scale.z, _transform.m[10] *= _scale.z;
905 : }
906 :
907 : // If skew is needed, apply skew and then anchor point
908 103778 : if (needsSkewMatrix) {
909 0 : Mat4 skewMatrix(1, (float) tanf(_skew.y), 0, 0, (float) tanf(_skew.x), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
910 :
911 0 : _transform = _transform * skewMatrix;
912 :
913 : // adjust anchor point
914 0 : if (anchorPointInPoints != Vec2::ZERO) {
915 0 : _transform.m[12] += _transform.m[0] * -anchorPointInPoints.x + _transform.m[4] * -anchorPointInPoints.y;
916 0 : _transform.m[13] += _transform.m[1] * -anchorPointInPoints.x + _transform.m[5] * -anchorPointInPoints.y;
917 : }
918 : }
919 :
920 103778 : _transformCacheDirty = false;
921 : }
922 :
923 199573 : return _transform;
924 : }
925 :
926 21 : void Node::setNodeToParentTransform(const Mat4& transform) {
927 21 : _transform = transform;
928 21 : _transformCacheDirty = false;
929 21 : _transformDirty = true;
930 21 : }
931 :
932 147 : const Mat4 &Node::getParentToNodeTransform() const {
933 147 : if (_transformInverseDirty) {
934 84 : _inverse = getNodeToParentTransform().getInversed();
935 84 : _transformInverseDirty = false;
936 : }
937 :
938 147 : return _inverse;
939 : }
940 :
941 15106 : Mat4 Node::getNodeToWorldTransform() const {
942 15106 : Mat4 t(this->getNodeToParentTransform());
943 :
944 52068 : for (Node *p = _parent; p != nullptr; p = p->getParent()) {
945 36962 : t = p->getNodeToParentTransform() * t;
946 : }
947 :
948 15106 : return t;
949 : }
950 :
951 9959 : Mat4 Node::getWorldToNodeTransform() const {
952 9959 : return getNodeToWorldTransform().getInversed();
953 : }
954 :
955 9959 : Vec2 Node::convertToNodeSpace(const Vec2 &worldPoint) const {
956 9959 : Mat4 tmp = getWorldToNodeTransform();
957 19918 : return tmp.transformPoint(worldPoint);
958 : }
959 :
960 4433 : Vec2 Node::convertToWorldSpace(const Vec2 &nodePoint) const {
961 4433 : Mat4 tmp = getNodeToWorldTransform();
962 8866 : return tmp.transformPoint(nodePoint);
963 : }
964 :
965 21 : Vec2 Node::convertToNodeSpaceAR(const Vec2 &worldPoint) const {
966 21 : Vec2 nodePoint(convertToNodeSpace(worldPoint));
967 21 : return nodePoint - Vec2(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y);
968 : }
969 :
970 21 : Vec2 Node::convertToWorldSpaceAR(const Vec2 &nodePoint) const {
971 21 : return convertToWorldSpace(nodePoint + Vec2(_contentSize.width * _anchorPoint.x, _contentSize.height * _anchorPoint.y));
972 : }
973 :
974 480 : void Node::setCascadeOpacityEnabled(bool cascadeOpacityEnabled) {
975 480 : if (_cascadeOpacityEnabled == cascadeOpacityEnabled) {
976 438 : return;
977 : }
978 :
979 42 : _cascadeOpacityEnabled = cascadeOpacityEnabled;
980 42 : if (_cascadeOpacityEnabled) {
981 21 : updateCascadeOpacity();
982 : } else {
983 21 : disableCascadeOpacity();
984 : }
985 : }
986 :
987 84 : void Node::setCascadeColorEnabled(bool cascadeColorEnabled) {
988 84 : if (_cascadeColorEnabled == cascadeColorEnabled) {
989 0 : return;
990 : }
991 :
992 84 : _cascadeColorEnabled = cascadeColorEnabled;
993 84 : if (_cascadeColorEnabled) {
994 63 : updateCascadeColor();
995 : } else {
996 21 : disableCascadeColor();
997 : }
998 : }
999 :
1000 9907 : void Node::setOpacity(float opacity) {
1001 9907 : _displayedColor.a = _realColor.a = opacity;
1002 9907 : updateCascadeOpacity();
1003 9907 : }
1004 :
1005 6097 : void Node::setOpacity(OpacityValue value) {
1006 6097 : setOpacity(value.get() / 255.0f);
1007 6097 : }
1008 :
1009 6839362 : void Node::updateDisplayedOpacity(float parentOpacity) {
1010 6839362 : _displayedColor.a = _realColor.a * parentOpacity;
1011 :
1012 6839362 : updateColor();
1013 :
1014 6839362 : if (_cascadeOpacityEnabled) {
1015 13577210 : for (const auto &child : _children) {
1016 6737848 : child->updateDisplayedOpacity(_displayedColor.a);
1017 : }
1018 : }
1019 6839362 : }
1020 :
1021 377506 : void Node::setColor(const Color4F& color, bool withOpacity) {
1022 377506 : if (withOpacity && _realColor.a != color.a) {
1023 5307 : _displayedColor = _realColor = color;
1024 :
1025 5307 : updateCascadeColor();
1026 5307 : updateCascadeOpacity();
1027 : } else {
1028 372199 : _realColor = Color4F(color.r, color.g, color.b, _realColor.a);
1029 372199 : _displayedColor = Color4F(color.r, color.g, color.b, _displayedColor.a);
1030 :
1031 372199 : updateCascadeColor();
1032 : }
1033 377506 : }
1034 :
1035 378154 : void Node::updateDisplayedColor(const Color4F &parentColor) {
1036 378154 : _displayedColor.r = _realColor.r * parentColor.r;
1037 378154 : _displayedColor.g = _realColor.g * parentColor.g;
1038 378154 : _displayedColor.b = _realColor.b * parentColor.b;
1039 378154 : updateColor();
1040 :
1041 378154 : if (_cascadeColorEnabled) {
1042 911 : for (const auto &child : _children) {
1043 501 : child->updateDisplayedColor(_displayedColor);
1044 : }
1045 : }
1046 378154 : }
1047 :
1048 :
1049 101493 : void Node::updateCascadeOpacity() {
1050 101493 : float parentOpacity = 1.0f;
1051 :
1052 101493 : if (_parent != nullptr && _parent->isCascadeOpacityEnabled()) {
1053 49343 : parentOpacity = _parent->getDisplayedOpacity();
1054 : }
1055 :
1056 101493 : updateDisplayedOpacity(parentOpacity);
1057 101493 : }
1058 :
1059 21 : void Node::disableCascadeOpacity() {
1060 21 : _displayedColor.a = _realColor.a;
1061 :
1062 42 : for (const auto &child : _children) {
1063 21 : child->updateDisplayedOpacity(1.0f);
1064 : }
1065 21 : }
1066 :
1067 377632 : void Node::updateCascadeColor() {
1068 377632 : Color4F parentColor = Color4F::WHITE;
1069 377632 : if (_parent && _parent->isCascadeColorEnabled()) {
1070 42 : parentColor = _parent->getDisplayedColor();
1071 : }
1072 :
1073 377632 : updateDisplayedColor(parentColor);
1074 377632 : }
1075 :
1076 21 : void Node::disableCascadeColor() {
1077 42 : for (const auto &child : _children) {
1078 21 : child->updateDisplayedColor(Color4F::WHITE);
1079 : }
1080 21 : }
1081 :
1082 115802 : void Node::draw(FrameInfo &info, NodeFlags flags) {
1083 :
1084 115802 : }
1085 :
1086 705069 : bool Node::visitGeometry(FrameInfo &info, NodeFlags parentFlags) {
1087 1410138 : return wrapVisit(info, parentFlags, [&] (NodeFlags flags, bool visibleByCamera) {
1088 406663 : auto c = _children;
1089 1102194 : for (auto &it : c) {
1090 695531 : it->visitGeometry(info, flags);
1091 : }
1092 1816801 : }, false);
1093 : }
1094 :
1095 628851 : bool Node::visitDraw(FrameInfo &info, NodeFlags parentFlags) {
1096 1257702 : return wrapVisit(info, parentFlags, [&] (NodeFlags flags, bool visibleByCamera) {
1097 404351 : size_t i = 0;
1098 :
1099 404351 : if (!_children.empty()) {
1100 262435 : sortAllChildren();
1101 :
1102 262435 : auto c = _children;
1103 :
1104 : // draw children zOrder < 0
1105 352377 : for (; i < c.size(); i++) {
1106 352377 : auto node = c.at(i);
1107 :
1108 352377 : if (node && node->_zOrder < ZOrder(0))
1109 89942 : node->visitDraw(info, flags);
1110 : else
1111 262435 : break;
1112 352377 : }
1113 :
1114 262435 : visitSelf(info, flags, visibleByCamera);
1115 :
1116 862600 : for (auto it = c.cbegin() + i; it != c.cend(); ++it) {
1117 600165 : (*it)->visitDraw(info, flags);
1118 : }
1119 262435 : } else {
1120 141916 : visitSelf(info, flags, visibleByCamera);
1121 : }
1122 1662053 : }, true);
1123 : }
1124 :
1125 285 : void Node::scheduleUpdate() {
1126 285 : if (!_scheduled) {
1127 285 : _scheduled = true;
1128 285 : if (_running) {
1129 201 : _scheduler->scheduleUpdate(this, 0, _paused);
1130 : }
1131 : }
1132 285 : }
1133 :
1134 68766 : void Node::unscheduleUpdate() {
1135 68766 : if (_scheduled) {
1136 180 : if (_running) {
1137 180 : _scheduler->unschedule(this);
1138 : }
1139 180 : _scheduled = false;
1140 : }
1141 68766 : }
1142 :
1143 8717 : bool Node::isTouched(const Vec2 &location, float padding) {
1144 8717 : Vec2 point = convertToNodeSpace(location);
1145 17434 : return isTouchedNodeSpace(point, padding);
1146 : }
1147 :
1148 8717 : bool Node::isTouchedNodeSpace(const Vec2 &point, float padding) {
1149 8717 : if (!isVisible()) {
1150 0 : return false;
1151 : }
1152 :
1153 8717 : const Size2 &size = getContentSize();
1154 8717 : if (point.x > -padding && point.y > -padding
1155 6387 : && point.x < size.width + padding
1156 4768 : && point.y < size.height + padding) {
1157 4085 : return true;
1158 : } else {
1159 4632 : return false;
1160 : }
1161 : }
1162 :
1163 21 : void Node::setOnEnterCallback(Function<void(Scene *)> &&cb) {
1164 21 : _onEnterCallback = move(cb);
1165 21 : }
1166 :
1167 21 : void Node::setOnExitCallback(Function<void()> &&cb) {
1168 21 : _onExitCallback = move(cb);
1169 21 : }
1170 :
1171 900 : void Node::setOnContentSizeDirtyCallback(Function<void()> &&cb) {
1172 900 : _onContentSizeDirtyCallback = move(cb);
1173 900 : }
1174 :
1175 132 : void Node::setOnTransformDirtyCallback(Function<void(const Mat4 &)> &&cb) {
1176 132 : _onTransformDirtyCallback = move(cb);
1177 132 : }
1178 :
1179 21 : void Node::setOnReorderChildDirtyCallback(Function<void()> &&cb) {
1180 21 : _onReorderChildDirtyCallback = move(cb);
1181 21 : }
1182 :
1183 146917 : Mat4 Node::transform(const Mat4 &parentTransform) {
1184 146917 : return parentTransform * this->getNodeToParentTransform();
1185 : }
1186 :
1187 813514 : NodeFlags Node::processParentFlags(FrameInfo &info, NodeFlags parentFlags) {
1188 813514 : NodeFlags flags = parentFlags;
1189 :
1190 813514 : if (_transformDirty) {
1191 103652 : onTransformDirty(info.modelTransformStack.back());
1192 : }
1193 :
1194 813514 : if ((flags & NodeFlags::DirtyMask) != NodeFlags::None || _transformDirty || _contentSizeDirty) {
1195 146917 : _modelViewTransform = this->transform(info.modelTransformStack.back());
1196 :
1197 146917 : onGlobalTransformDirty(info.modelTransformStack.back());
1198 : }
1199 :
1200 813514 : if (_transformDirty) {
1201 103652 : _transformDirty = false;
1202 103652 : flags |= NodeFlags::TransformDirty;
1203 : }
1204 :
1205 813514 : if (_contentSizeDirty) {
1206 92401 : onContentSizeDirty();
1207 92401 : _contentSizeDirty = false;
1208 92401 : flags |= NodeFlags::ContentSizeDirty;
1209 : }
1210 :
1211 813514 : return flags;
1212 : }
1213 :
1214 406851 : void Node::visitSelf(FrameInfo &info, NodeFlags flags, bool visibleByCamera) {
1215 592050 : for (auto &it : _components) {
1216 185199 : it->visit(info, flags);
1217 : }
1218 :
1219 449990 : for (auto &it : _inputEvents) {
1220 43139 : if (it->isEnabled()) {
1221 33580 : auto dedicated = it->getDedicatedFocus();
1222 33580 : info.input->addListener(it, dedicated == 0 ? info.focusValue : dedicated);
1223 : }
1224 : }
1225 :
1226 406851 : if (!_inputEvents.empty()) {
1227 42362 : info.input->updateFocus(info.focusValue);
1228 : }
1229 :
1230 : // self draw
1231 406851 : if (visibleByCamera) {
1232 406851 : this->draw(info, flags);
1233 : }
1234 406851 : }
1235 :
1236 1336420 : bool Node::wrapVisit(FrameInfo &info, NodeFlags parentFlags, const Callback<void(NodeFlags, bool visible)> &cb, bool useContext) {
1237 1336420 : if (!_visible) {
1238 522906 : return false;
1239 : }
1240 :
1241 813514 : bool hasFrameContext = false;
1242 813514 : if (useContext && _frameContext) {
1243 397313 : if (_parent && _parent->getFrameContext() != _frameContext) {
1244 9538 : info.pushContext(_frameContext);
1245 9538 : hasFrameContext = true;
1246 : }
1247 : }
1248 :
1249 813514 : NodeFlags flags = processParentFlags(info, parentFlags);
1250 :
1251 813514 : if (!_running || !_visible) {
1252 0 : if (hasFrameContext) {
1253 0 : info.popContext();
1254 : }
1255 0 : return false;
1256 : }
1257 :
1258 813514 : auto focus = _focus;
1259 813514 : info.focusValue += focus;
1260 :
1261 813514 : auto order = getLocalZOrder();
1262 :
1263 813514 : bool visibleByCamera = true;
1264 :
1265 813514 : info.modelTransformStack.push_back(_modelViewTransform);
1266 813514 : if (order != ZOrderTransparent) {
1267 794438 : info.zPath.push_back(order);
1268 : }
1269 :
1270 813514 : if (_depthIndex > 0.0f) {
1271 48720 : info.depthStack.push_back(std::max(info.depthStack.back(), _depthIndex));
1272 : }
1273 :
1274 813514 : memory::vector< memory::vector<Rc<Component>> * > components;
1275 :
1276 1183787 : for (auto &it : _components) {
1277 370273 : if (it->isEnabled() && it->getFrameTag() != InvalidTag) {
1278 112920 : components.emplace_back(info.pushComponent(it));
1279 : }
1280 : }
1281 :
1282 813514 : cb(flags, visibleByCamera);
1283 :
1284 926434 : for (auto &it : components) {
1285 112920 : info.popComponent(it);
1286 : }
1287 :
1288 813514 : if (_depthIndex > 0.0f) {
1289 48720 : info.depthStack.pop_back();
1290 : }
1291 :
1292 813514 : if (order != ZOrderTransparent) {
1293 794438 : info.zPath.pop_back();
1294 : }
1295 813514 : info.modelTransformStack.pop_back();
1296 :
1297 813514 : if (hasFrameContext) {
1298 9538 : info.popContext();
1299 : }
1300 :
1301 813514 : info.focusValue -= focus;
1302 :
1303 813514 : return true;
1304 813514 : }
1305 :
1306 498241 : float Node::getMaxDepthIndex() const {
1307 498241 : float val = _depthIndex;
1308 1237698 : for (auto &it : _children) {
1309 739457 : if (it->isVisible()) {
1310 386839 : val = std::max(it->getMaxDepthIndex(), val);
1311 : }
1312 : }
1313 498241 : return val;
1314 : }
1315 :
1316 0 : void Node::retainFocus() {
1317 0 : ++ _focus;
1318 0 : }
1319 :
1320 0 : void Node::releaseFocus() {
1321 0 : if (_focus > 0) {
1322 0 : -- _focus;
1323 : }
1324 0 : }
1325 :
1326 21 : void Node::clearFocus() {
1327 21 : _focus = 0;
1328 21 : }
1329 :
1330 : }
|