LCOV - code coverage report
Current view: top level - xenolith/scene/nodes - XLNode.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 727 785 92.6 %
Date: 2024-05-12 00:16:13 Functions: 114 116 98.3 %

          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             : }

Generated by: LCOV version 1.14