LCOV - code coverage report
Current view: top level - xenolith/scene/nodes - XLDynamicStateNode.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 89 96 92.7 %
Date: 2024-05-12 00:16:13 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2022 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 "XLDynamicStateNode.h"
      25             : #include "XLFrameInfo.h"
      26             : 
      27             : namespace STAPPLER_VERSIONIZED stappler::xenolith {
      28             : 
      29       50264 : bool DynamicStateNode::init() {
      30       50264 :         return Node::init();
      31             : }
      32             : 
      33          84 : void DynamicStateNode::setStateApplyMode(StateApplyMode value) {
      34          84 :         _applyMode = value;
      35          84 : }
      36             : 
      37          21 : void DynamicStateNode::setIgnoreParentState(bool val) {
      38          21 :         _ignoreParentState = val;
      39          21 : }
      40             : 
      41      569314 : bool DynamicStateNode::visitDraw(FrameInfo &info, NodeFlags parentFlags) {
      42      569314 :         if (_applyMode == DoNotApply || info.contextStack.empty()) {
      43      514331 :                 return Node::visitDraw(info, parentFlags);
      44             :         }
      45             : 
      46       54983 :         if (!_visible) {
      47       41647 :                 return false;
      48             :         }
      49             : 
      50       13336 :         auto &ctx = info.contextStack.back();
      51       13336 :         auto prevStateId = ctx->getCurrentState();
      52       13336 :         auto currentState = ctx->getState(prevStateId);
      53             :         /*if (!currentState) {
      54             :                 // invalid state
      55             :                 return Node::visitDraw(info, parentFlags);
      56             :         }*/
      57             : 
      58       13336 :         auto newState = updateDynamicState(currentState ? *currentState : DrawStateValues());
      59             : 
      60       13336 :         StateId stateId = maxOf<StateId>();
      61             : 
      62       13336 :         if (newState.enabled == core::DynamicState::None) {
      63             :                 // no need to enable anything, drop to 0
      64       10836 :                 if (prevStateId == maxOf<StateId>()) {
      65       10836 :                         return Node::visitDraw(info, parentFlags);
      66             :                 }
      67             :                 // perform with default id
      68             :         } else {
      69        2500 :                 stateId = ctx->addState(newState);
      70             :         }
      71             : 
      72        5000 :         return wrapVisit(info, parentFlags, [&] (NodeFlags flags, bool visibleByCamera) {
      73        2500 :                 if (!_children.empty()) {
      74        1702 :                         sortAllChildren();
      75             : 
      76        1702 :                         switch (_applyMode) {
      77        1429 :                         case ApplyForAll:
      78             :                         case ApplyForNodesBelow:
      79        1429 :                                 ctx->stateStack.push_back(stateId);
      80        1429 :                                 break;
      81         273 :                         default: break;
      82             :                         }
      83             : 
      84        1702 :                         size_t i = 0;
      85             : 
      86             :                         // draw children zOrder < 0
      87        2479 :                         for (; i < _children.size(); i++) {
      88        2479 :                                 auto node = _children.at(i);
      89             : 
      90        2479 :                                 if (node && node->getLocalZOrder() < ZOrder(0))
      91         777 :                                         node->visitDraw(info, flags);
      92             :                                 else
      93        1702 :                                         break;
      94        2479 :                         }
      95             : 
      96        1702 :                         switch (_applyMode) {
      97         273 :                         case ApplyForNodesAbove:
      98         273 :                                 ctx->stateStack.push_back(stateId);
      99         273 :                                 break;
     100        1429 :                         default: break;
     101             :                         }
     102             : 
     103        1702 :                         visitSelf(info, flags, visibleByCamera);
     104             : 
     105        1702 :                         switch (_applyMode) {
     106         777 :                         case ApplyForNodesBelow:
     107         777 :                                 ctx->stateStack.pop_back();
     108         777 :                                 break;
     109         925 :                         default: break;
     110             :                         }
     111             : 
     112        6620 :                         for (auto it = _children.cbegin() + i; it != _children.cend(); ++it) {
     113        4918 :                                 (*it)->visitDraw(info, flags);
     114             :                         }
     115             : 
     116        1702 :                         switch (_applyMode) {
     117         925 :                         case ApplyForAll:
     118             :                         case ApplyForNodesAbove:
     119         925 :                                 ctx->stateStack.pop_back();
     120         925 :                                 break;
     121         777 :                         default: break;
     122             :                         }
     123             : 
     124             :                 } else {
     125         798 :                         ctx->stateStack.push_back(stateId);
     126             : 
     127         798 :                         visitSelf(info, flags, visibleByCamera);
     128             : 
     129         798 :                         ctx->stateStack.pop_back();
     130             :                 }
     131        5000 :         }, true);
     132             : 
     133             :         return true;
     134       13336 : }
     135             : 
     136         147 : void DynamicStateNode::enableScissor(Padding outline) {
     137         147 :         _scissorEnabled = true;
     138         147 :         _scissorOutline = outline;
     139         147 : }
     140             : 
     141          63 : void DynamicStateNode::disableScissor() {
     142          63 :         _scissorEnabled = false;
     143          63 : }
     144             : 
     145       13336 : DrawStateValues DynamicStateNode::updateDynamicState(const DrawStateValues &values) const {
     146        4412 :         auto getViewRect = [&, this] {
     147        2206 :             Vec2 bottomLeft = convertToWorldSpace(Vec2(-_scissorOutline.left, -_scissorOutline.bottom));
     148        2206 :                 Vec2 topRight = convertToWorldSpace(Vec2(_contentSize.width + _scissorOutline.right, _contentSize.height + _scissorOutline.top));
     149             : 
     150        2206 :                 if (bottomLeft.x > topRight.x) {
     151           0 :                         float b = topRight.x;
     152           0 :                         topRight.x = bottomLeft.x;
     153           0 :                         bottomLeft.x = b;
     154             :                 }
     155             : 
     156        2206 :                 if (bottomLeft.y > topRight.y) {
     157           0 :                         float b = topRight.y;
     158           0 :                         topRight.y = bottomLeft.y;
     159           0 :                         bottomLeft.y = b;
     160             :                 }
     161             : 
     162        4412 :                 return URect{uint32_t(roundf(bottomLeft.x)), uint32_t(roundf(bottomLeft.y)),
     163        2206 :                         uint32_t(roundf(topRight.x - bottomLeft.x)), uint32_t(roundf(topRight.y - bottomLeft.y))};
     164       13336 :         };
     165             : 
     166             : 
     167       13336 :         DrawStateValues ret(_ignoreParentState ? DrawStateValues() : values);
     168       13336 :         if (_scissorEnabled) {
     169        2206 :                 auto viewRect = getViewRect();
     170        2206 :                 if ((ret.enabled & core::DynamicState::Scissor) == core::DynamicState::None) {
     171        2059 :                         ret.enabled |= core::DynamicState::Scissor;
     172        2059 :                         ret.scissor = viewRect;
     173         147 :                 } else if (ret.scissor.intersectsRect(viewRect)) {
     174          21 :                         ret.scissor = URect{
     175          21 :                                 std::max(ret.scissor.x, viewRect.x),
     176          21 :                                 std::max(ret.scissor.y, viewRect.y),
     177          21 :                                 std::min(ret.scissor.width, viewRect.width),
     178          21 :                                 std::min(ret.scissor.height, viewRect.height),
     179             :                         };
     180             :                 }
     181             :         }
     182       26672 :         return ret;
     183           0 : }
     184             : 
     185             : }

Generated by: LCOV version 1.14