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