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 "XLScene.h" 25 : 26 : #include "XLFrameInfo.h" 27 : #include "XLInputDispatcher.h" 28 : #include "XLDirector.h" 29 : #include "XLSceneContent.h" 30 : #include "XLCoreFrameRequest.h" 31 : 32 : namespace STAPPLER_VERSIONIZED stappler::xenolith { 33 : 34 0 : static void Scene_findUnresolvedInputs(const memory::vector<core::AttachmentData *> &queue, 35 : const memory::set<const core::AttachmentData *> &resolved) { 36 0 : for (auto &it : queue) { 37 0 : auto iit = resolved.find(it); 38 0 : if (iit == resolved.end()) { 39 0 : log::warn("Scene", "No input defined for attachment: ", it->key); 40 : } 41 : } 42 0 : } 43 : 44 21 : Scene::~Scene() { 45 21 : _queue = nullptr; 46 21 : } 47 : 48 21 : bool Scene::init(Queue::Builder &&builder, const core::FrameContraints &constraints) { 49 21 : if (!Node::init()) { 50 0 : return false; 51 : } 52 : 53 21 : setLocalZOrder(ZOrderTransparent); 54 : 55 21 : _queue = makeQueue(move(builder)); 56 : 57 21 : setFrameConstraints(_constraints); 58 : 59 21 : return true; 60 : } 61 : 62 9538 : void Scene::renderRequest(const Rc<FrameRequest> &req) { 63 9538 : if (!_director) { 64 0 : return; 65 : } 66 : 67 9538 : Size2 scaledExtent(_constraints.extent.width / _constraints.density, _constraints.extent.height / _constraints.density); 68 : 69 9538 : FrameInfo info; 70 9538 : info.request = req; 71 9538 : info.pool = req->getPool(); 72 : 73 9538 : render(info); 74 : 75 9538 : if (info.resolvedInputs.size() != _queue->getInputAttachments().size()) { 76 0 : Scene_findUnresolvedInputs(_queue->getInputAttachments(), info.resolvedInputs); 77 : } 78 9538 : } 79 : 80 9538 : void Scene::render(FrameInfo &info) { 81 9538 : info.director = _director; 82 9538 : info.scene = this; 83 9538 : info.zPath.reserve(8); 84 : 85 9538 : info.viewProjectionStack.reserve(2); 86 9538 : info.viewProjectionStack.push_back(_director->getGeneralProjection()); 87 : 88 9538 : info.modelTransformStack.reserve(8); 89 9538 : info.modelTransformStack.push_back(Mat4::IDENTITY); 90 : 91 9538 : info.depthStack.reserve(4); 92 9538 : info.depthStack.push_back(0.0f); 93 : 94 9538 : auto eventDispatcher = _director->getInputDispatcher(); 95 : 96 9538 : info.input = eventDispatcher->acquireNewStorage(); 97 : 98 9538 : visitGeometry(info, NodeFlags::None); 99 9538 : visitDraw(info, NodeFlags::None); 100 : 101 9538 : eventDispatcher->commitStorage(move(info.input)); 102 9538 : } 103 : 104 21 : void Scene::onEnter(Scene *scene) { 105 21 : Node::onEnter(scene); 106 21 : } 107 : 108 21 : void Scene::onExit() { 109 21 : Node::onExit(); 110 21 : } 111 : 112 21 : void Scene::onContentSizeDirty() { 113 21 : Node::onContentSizeDirty(); 114 : 115 21 : setAnchorPoint(Anchor::Middle); 116 21 : setPosition(Vec2((_contentSize * _constraints.density) / 2.0f)); 117 : 118 21 : updateContentNode(_content); 119 : 120 : #if DEBUG 121 21 : log::info("Scene", "ContentSize: ", _contentSize, " density: ", _constraints.density); 122 : #endif 123 21 : } 124 : 125 21 : void Scene::setContent(SceneContent *content) { 126 21 : if (_content) { 127 0 : _content->removeFromParent(true); 128 : } 129 21 : _content = nullptr; 130 21 : if (content) { 131 21 : _content = addChild(content); 132 21 : updateContentNode(_content); 133 : } 134 21 : } 135 : 136 21 : void Scene::onPresented(Director *dir) { 137 21 : _director = dir; 138 21 : if (getContentSize() == Size2::ZERO) { 139 0 : setContentSize(_constraints.getScreenSize() / _constraints.density); 140 : } 141 : 142 21 : if (auto res = _queue->getInternalResource()) { 143 21 : dir->getResourceCache()->addResource(res); 144 21 : } 145 : 146 21 : onEnter(this); 147 21 : } 148 : 149 21 : void Scene::onFinished(Director *dir) { 150 21 : onExit(); 151 : 152 21 : if (_director == dir) { 153 21 : if (auto res = _queue->getInternalResource()) { 154 21 : auto cache = dir->getResourceCache(); 155 21 : if (cache) { 156 21 : cache->removeResource(res->getName()); 157 : } 158 42 : } 159 : 160 21 : _director = nullptr; 161 : } 162 21 : } 163 : 164 9538 : void Scene::onFrameStarted(FrameRequest &req) { 165 9538 : req.setSceneId(retain()); 166 9538 : } 167 : 168 9538 : void Scene::onFrameEnded(FrameRequest &req) { 169 9538 : release(req.getSceneId()); 170 9538 : } 171 : 172 9538 : void Scene::onFrameAttached(const FrameHandle *frame) { 173 : 174 9538 : } 175 : 176 9538 : void Scene::onFrameDetached(const FrameHandle *frame) { 177 : 178 9538 : } 179 : 180 210 : void Scene::setFrameConstraints(const core::FrameContraints &constraints) { 181 210 : if (_constraints != constraints) { 182 189 : auto size = constraints.getScreenSize(); 183 : 184 189 : _constraints = constraints; 185 : 186 189 : setContentSize(size / _constraints.density); 187 189 : setScale(_constraints.density); 188 189 : _contentSizeDirty = true; 189 : 190 189 : setPosition(Vec2((_contentSize * _constraints.density) / 2.0f)); 191 : 192 189 : updateContentNode(_content); 193 : } 194 210 : } 195 : 196 3329 : const Size2& Scene::getContentSize() const { 197 3329 : return _content ? _content->getContentSize() : _contentSize; 198 : } 199 : 200 42 : void Scene::setClipContent(bool value) { 201 42 : if (_content) { 202 42 : if (isClipContent() != value) { 203 42 : if (value) { 204 21 : _content->enableScissor(); 205 : } else { 206 21 : _content->disableScissor(); 207 : } 208 : } 209 : } 210 42 : } 211 : 212 84 : bool Scene::isClipContent() const { 213 84 : return _content ? _content->isScissorEnabled() : false; 214 : } 215 : 216 21 : auto Scene::makeQueue(Queue::Builder &&builder) -> Rc<Queue> { 217 21 : builder.setBeginCallback([this] (FrameRequest &frame) { 218 9538 : onFrameStarted(frame); 219 9538 : }); 220 21 : builder.setEndCallback([this] (FrameRequest &frame) { 221 9538 : onFrameEnded(frame); 222 9538 : }); 223 21 : builder.setAttachCallback([this] (const FrameHandle *frame) { 224 9538 : onFrameAttached(frame); 225 9538 : }); 226 21 : builder.setDetachCallback([this] (const FrameHandle *frame) { 227 9538 : onFrameDetached(frame); 228 9538 : }); 229 : 230 21 : return Rc<Queue>::create(move(builder)); 231 : } 232 : 233 231 : void Scene::updateContentNode(SceneContent *content) { 234 231 : if (content) { 235 231 : auto padding = _constraints.contentPadding / _constraints.density; 236 : 237 231 : content->setPosition(Vec2(padding.left, padding.bottom)); 238 231 : content->setContentSize(Size2(_contentSize.width - padding.horizontal(), _contentSize.height - padding.vertical())); 239 231 : content->setAnchorPoint(Anchor::BottomLeft); 240 231 : content->setDecorationPadding(padding); 241 : } 242 231 : } 243 : 244 : }