LCOV - code coverage report
Current view: top level - xenolith/renderer/basic2d - XL2dScene.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 119 205 58.0 %
Date: 2024-05-12 00:16:13 Functions: 17 28 60.7 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XL2dLayer.h"
      24             : #include "XL2dLabel.h"
      25             : #include "XL2dScene.h"
      26             : #include "XL2dVectorCanvas.h"
      27             : #include "XL2dVectorSprite.h"
      28             : #include "XLView.h"
      29             : #include "XLDirector.h"
      30             : #include "XLInputListener.h"
      31             : #include "XLSceneContent.h"
      32             : #include "XLFrameInfo.h"
      33             : #include "backend/vk/XL2dVkShadowPass.h"
      34             : 
      35             : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d {
      36             : 
      37             : class Scene2d::FpsDisplay : public Layer {
      38             : public:
      39             :         enum DisplayMode {
      40             :                 Fps,
      41             :                 Vertexes,
      42             :                 Cache,
      43             :                 Full,
      44             :                 Disabled,
      45             :         };
      46             : 
      47          20 :         virtual ~FpsDisplay() { }
      48             : 
      49             :         virtual bool init(font::FontController *fontController);
      50             :         virtual void update(const UpdateTime &) override;
      51             : 
      52             :         virtual bool visitDraw(FrameInfo &, NodeFlags parentFlags) override;
      53             : 
      54             :         void incrementMode();
      55             : 
      56             : protected:
      57             :         using Layer::init;
      58             : 
      59             :         uint32_t _frames = 0;
      60             :         Label *_label = nullptr;
      61             :         DisplayMode _mode = Fps;
      62             : };
      63             : 
      64          10 : bool Scene2d::FpsDisplay::init(font::FontController *fontController) {
      65          10 :         if (!Layer::init(Color::White)) {
      66           0 :                 return false;
      67             :         }
      68             : 
      69          10 :         if (fontController) {
      70          10 :                 _label = addChild(Rc<Label>::create(fontController), Node::ZOrderMax);
      71          10 :                 _label->setString("0.0\n0.0\n0.0\n0 0 0 0");
      72          10 :                 _label->setFontFamily("monospace");
      73          10 :                 _label->setAnchorPoint(Anchor::BottomLeft);
      74          10 :                 _label->setColor(Color::Black, true);
      75          10 :                 _label->setFontSize(16);
      76          10 :                 _label->setOnContentSizeDirtyCallback([this] {
      77        1401 :                         setContentSize(_label->getContentSize());
      78        1401 :                 });
      79          10 :                 _label->setPersistentLayout(true);
      80          10 :                 _label->addCommandFlags(CommandFlags::DoNotCount);
      81             :         }
      82             : 
      83          10 :         addCommandFlags(CommandFlags::DoNotCount);
      84          10 :         scheduleUpdate();
      85             : 
      86          10 :         return true;
      87             : }
      88             : 
      89        4650 : void Scene2d::FpsDisplay::update(const UpdateTime &) {
      90        4650 :         if (_director) {
      91        4650 :                 auto fps = _director->getAvgFps();
      92        4650 :                 auto spf = _director->getSpf();
      93        4650 :                 auto local = _director->getLocalFrameTime();
      94        4650 :                 auto stat = _director->getDrawStat();
      95        4650 :                 auto tm = _director->getDirectorFrameTime();
      96        4650 :                 auto vertex = stat.vertexInputTime / float(1000);
      97             : 
      98        4650 :                 if (_label) {
      99        4650 :                         String str;
     100        4650 :                         switch (_mode) {
     101        4650 :                         case Fps:
     102        9300 :                                 str = toString(std::setprecision(3),
     103             :                                         "FPS: ", fps, " SPF: ", spf, "\nGPU: ", local, "\nDir: ", tm, " Ver: ", vertex,
     104        4650 :                                         "\nF12 to switch");
     105        4650 :                                 break;
     106           0 :                         case Vertexes:
     107           0 :                                 str = toString(std::setprecision(3),
     108             :                                         "V:", stat.vertexes, " T:", stat.triangles, "\nZ:", stat.zPaths, " C:", stat.drawCalls, " M: ", stat.materials, "\n",
     109             :                                         stat.solidCmds, "/", stat.surfaceCmds, "/", stat.transparentCmds,
     110           0 :                                         "\nF12 to switch");
     111           0 :                                 break;
     112           0 :                         case Cache:
     113           0 :                                 str = toString(std::setprecision(3),
     114             :                                         "Cache:", stat.cachedFramebuffers, "/", stat.cachedImages, "/", stat.cachedImageViews,
     115           0 :                                         "\nF12 to switch");
     116           0 :                                 break;
     117           0 :                         case Full:
     118           0 :                                 str = toString(std::setprecision(3),
     119             :                                         "FPS: ", fps, " SPF: ", spf, "\nGPU: ", local, "\nDir: ", tm, " Ver: ", vertex, "\n",
     120             :                                         "V:", stat.vertexes, " T:", stat.triangles, "\nZ:", stat.zPaths, " C:", stat.drawCalls, " M: ", stat.materials, "\n",
     121             :                                         stat.solidCmds, "/", stat.surfaceCmds, "/", stat.transparentCmds, "\n",
     122             :                                         "Cache:", stat.cachedFramebuffers, "/", stat.cachedImages, "/", stat.cachedImageViews,
     123           0 :                                         "\nF12 to switch");
     124           0 :                                 break;
     125           0 :                         default:
     126           0 :                                 break;
     127             :                         }
     128        4650 :                         _label->setString(str);
     129        4650 :                 }
     130        4650 :                 ++ _frames;
     131             :         }
     132        4650 : }
     133             : 
     134        4650 : bool Scene2d::FpsDisplay::visitDraw(FrameInfo &frame, NodeFlags parentFlags) {
     135             :         // place above any shadows
     136        4650 :         frame.depthStack.emplace_back(100.0f);
     137        4650 :         auto ret = Layer::visitDraw(frame, parentFlags);
     138        4650 :         frame.depthStack.pop_back();
     139        4650 :         return ret;
     140             : }
     141             : 
     142           0 : void Scene2d::FpsDisplay::incrementMode() {
     143           0 :         _mode = DisplayMode(toInt(_mode) + 1);
     144           0 :         if (_mode > Disabled) {
     145           0 :                 _mode = Fps;
     146             :         }
     147             : 
     148           0 :         setVisible(_mode != Disabled);
     149           0 : }
     150             : 
     151           0 : bool Scene2d::init(Application *app, const core::FrameContraints &constraints) {
     152           0 :         return init(app, [] (Queue::Builder &) { }, constraints);
     153             : }
     154             : 
     155           0 : bool Scene2d::init(Application *app, const Callback<void(Queue::Builder &)> &cb, const core::FrameContraints &constraints) {
     156           0 :         core::Queue::Builder builder("Loader");
     157             : 
     158           0 :         basic2d::vk::ShadowPass::RenderQueueInfo info{
     159           0 :                 app, Extent2(constraints.extent.width, constraints.extent.height), basic2d::vk::ShadowPass::Flags::None
     160           0 :         };
     161             : 
     162           0 :         basic2d::vk::ShadowPass::makeDefaultRenderQueue(builder, info);
     163             : 
     164           0 :         cb(builder);
     165             : 
     166           0 :         if (!init(move(builder), constraints)) {
     167           0 :                 return false;
     168             :         }
     169             : 
     170           0 :         return true;
     171           0 : }
     172             : 
     173          10 : bool Scene2d::init(Queue::Builder &&builder, const core::FrameContraints &constraints) {
     174          10 :         if (!xenolith::Scene::init(move(builder), constraints)) {
     175           0 :                 return false;
     176             :         }
     177             : 
     178          10 :         initialize();
     179             : 
     180          10 :         return true;
     181             : }
     182             : 
     183        4650 : void Scene2d::update(const UpdateTime &time) {
     184        4650 :         xenolith::Scene::update(time);
     185        4650 : }
     186             : 
     187          10 : void Scene2d::onContentSizeDirty() {
     188          10 :         xenolith::Scene::onContentSizeDirty();
     189             : 
     190          10 :         if (_fps) {
     191          10 :                 _fps->setPosition(Vec2(6.0f, 6.0f));
     192             :         }
     193             : 
     194          10 :         _pointerCenter->setPosition(_contentSize / 2.0f);
     195          10 : }
     196             : 
     197           0 : void Scene2d::setFpsVisible(bool value) {
     198           0 :         _fps->setVisible(value);
     199           0 : }
     200             : 
     201           0 : bool Scene2d::isFpsVisible() const {
     202           0 :         return _fps->isVisible();
     203             : }
     204             : 
     205          10 : void Scene2d::setContent(SceneContent *content) {
     206          10 :         xenolith::Scene::setContent(content);
     207             : 
     208          10 :         addContentNodes(_content);
     209          10 : }
     210             : 
     211          10 : void Scene2d::initialize() {
     212          10 :         _listener = addInputListener(Rc<InputListener>::create());
     213          10 :         _listener->addKeyRecognizer([this] (const GestureData &ev) {
     214           0 :                 if (ev.event == GestureEvent::Ended) {
     215           0 :                         _fps->incrementMode();
     216             :                 }
     217           0 :                 return true;
     218          10 :         }, InputListener::makeKeyMask({InputKeyCode::F12}));
     219             : 
     220          10 :         _listener->addKeyRecognizer([this] (const GestureData &ev) {
     221           0 :                 _pointerReal->setVisible(ev.event != GestureEvent::Ended && ev.event != GestureEvent::Cancelled);
     222           0 :                 _pointerVirtual->setVisible(ev.event != GestureEvent::Ended && ev.event != GestureEvent::Cancelled);
     223           0 :                 _pointerCenter->setVisible(ev.event != GestureEvent::Ended && ev.event != GestureEvent::Cancelled);
     224           0 :                 return true;
     225          10 :         }, InputListener::makeKeyMask({InputKeyCode::LEFT_CONTROL}));
     226             : 
     227          10 :         _listener->addTapRecognizer([this] (const GestureTap &ev) {
     228         360 :                 if (_fps->isTouched(ev.input->currentLocation)) {
     229           0 :                         _fps->incrementMode();
     230             :                 }
     231         360 :                 return true;
     232          10 :         }, InputListener::makeButtonMask({InputMouseButton::Touch}), 1);
     233             : 
     234          10 :         _listener->addTouchRecognizer([this] (const GestureData &ev) {
     235           0 :                 if ((ev.input->data.modifiers & InputModifier::Ctrl) == InputModifier::None) {
     236           0 :                         if (_data1.event != InputEventName::End && _data1.event != InputEventName::Cancel) {
     237             : 
     238           0 :                                 updateInputEventData(_data1, ev.input->data, _content->convertToWorldSpace(_pointerReal->getPosition().xy()), maxOf<uint32_t>() - 1);
     239           0 :                                 updateInputEventData(_data2, ev.input->data, _content->convertToWorldSpace(_pointerVirtual->getPosition().xy()), maxOf<uint32_t>() - 2);
     240             : 
     241           0 :                                 _data1.event = InputEventName::Cancel;
     242           0 :                                 _data2.event = InputEventName::Cancel;
     243             : 
     244           0 :                                 Vector<InputEventData> events{ _data1, _data2 };
     245             : 
     246           0 :                                 _scene->getDirector()->getView()->handleInputEvents(move(events));
     247           0 :                         }
     248           0 :                         return false;
     249             :                 }
     250             : 
     251           0 :                 if (ev.event == GestureEvent::Began) {
     252           0 :                         _listener->setExclusiveForTouch(ev.input->data.id);
     253             :                 }
     254             : 
     255           0 :                 updateInputEventData(_data1, ev.input->data, _content->convertToWorldSpace(_pointerReal->getPosition().xy()), maxOf<uint32_t>() - 1);
     256           0 :                 updateInputEventData(_data2, ev.input->data, _content->convertToWorldSpace(_pointerVirtual->getPosition().xy()), maxOf<uint32_t>() - 2);
     257             : 
     258           0 :                 Vector<InputEventData> events{ _data1, _data2 };
     259             : 
     260           0 :                 _scene->getDirector()->getView()->handleInputEvents(move(events));
     261             : 
     262           0 :                 return true;
     263          10 :         }, InputListener::makeButtonMask({InputMouseButton::MouseRight}));
     264             : 
     265          10 :         _listener->addTapRecognizer([this] (const GestureTap &tap) {
     266           0 :                 if ((tap.input->data.modifiers & InputModifier::Shift) != InputModifier::None
     267           0 :                                 && (tap.input->data.modifiers & InputModifier::Ctrl) != InputModifier::None) {
     268           0 :                         _pointerCenter->setPosition(_content->convertToNodeSpace(tap.input->currentLocation));
     269             :                 }
     270           0 :                 return true;
     271          10 :         }, InputListener::makeButtonMask({InputMouseButton::MouseRight}), 1);
     272             : 
     273          10 :         _listener->addMoveRecognizer([this] (const GestureData &ev) {
     274         367 :                 auto pos = _content->convertToNodeSpace(ev.input->currentLocation);
     275         367 :                 auto diff = pos - _pointerCenter->getPosition().xy();
     276             : 
     277         367 :                 _pointerReal->setPosition(pos);
     278         367 :                 _pointerVirtual->setPosition(pos - diff * 2.0f);
     279         367 :                 return true;
     280             :         });
     281             : 
     282             : #if NDEBUG
     283             :         _listener->setEnabled(false);
     284             : #endif
     285          10 : }
     286             : 
     287          10 : void Scene2d::addContentNodes(SceneContent *root) {
     288          10 :         if (_fps) {
     289           0 :                 _fps->removeFromParent(true);
     290           0 :                 _fps = nullptr;
     291             :         }
     292             : 
     293          10 :         if (_pointerReal) {
     294           0 :                 _pointerReal->removeFromParent(true);
     295           0 :                 _pointerReal = nullptr;
     296             :         }
     297             : 
     298          10 :         if (_pointerVirtual) {
     299           0 :                 _pointerVirtual->removeFromParent(true);
     300           0 :                 _pointerVirtual = nullptr;
     301             :         }
     302             : 
     303          10 :         if (_pointerCenter) {
     304           0 :                 _pointerCenter->removeFromParent(true);
     305           0 :                 _pointerCenter = nullptr;
     306             :         }
     307             : 
     308          10 :         if (root) {
     309          10 :                 auto mainLoop = Application::getInstance();
     310             : 
     311          10 :                 _fps = root->addChild(Rc<FpsDisplay>::create(mainLoop->getExtension<font::FontController>()), Node::ZOrderMax);
     312             : #if NDEBUG
     313             :                 _fps->setVisible(false);
     314             : #endif
     315             : 
     316             :                 do {
     317          10 :                         auto image = Rc<VectorImage>::create(Size2(24, 24));
     318          10 :                         image->addPath()->openForWriting([] (vg::PathWriter &writer) {
     319          10 :                                 writer.addCircle(12, 12, 12);
     320          10 :                         });
     321             : 
     322          10 :                         _pointerReal = root->addChild(Rc<VectorSprite>::create(move(image)), ZOrder::max());
     323          10 :                         _pointerReal->setAnchorPoint(Anchor::Middle);
     324          10 :                         _pointerReal->setContentSize(Size2(12, 12));
     325          10 :                         _pointerReal->setColor(Color::Red_500);
     326          10 :                         _pointerReal->setVisible(false);
     327          10 :                 } while (0);
     328             : 
     329             :                 do {
     330          10 :                         auto image = Rc<VectorImage>::create(Size2(24, 24));
     331          10 :                         image->addPath()->openForWriting([] (vg::PathWriter &writer) {
     332          10 :                                 writer.addCircle(12, 12, 12);
     333          10 :                         });
     334             : 
     335          10 :                         _pointerVirtual = root->addChild(Rc<VectorSprite>::create(move(image)), ZOrder::max());
     336          10 :                         _pointerVirtual->setAnchorPoint(Anchor::Middle);
     337          10 :                         _pointerVirtual->setContentSize(Size2(12, 12));
     338          10 :                         _pointerVirtual->setColor(Color::Blue_500);
     339          10 :                         _pointerVirtual->setVisible(false);
     340          10 :                 } while (0);
     341             : 
     342             :                 do {
     343          10 :                         auto image = Rc<VectorImage>::create(Size2(24, 24));
     344          10 :                         image->addPath()->openForWriting([] (vg::PathWriter &writer) {
     345          10 :                                 writer.addCircle(12, 12, 12);
     346          10 :                         });
     347             : 
     348          10 :                         _pointerCenter = root->addChild(Rc<VectorSprite>::create(move(image)), ZOrder::max());
     349          10 :                         _pointerCenter->setAnchorPoint(Anchor::Middle);
     350          10 :                         _pointerCenter->setContentSize(Size2(12, 12));
     351          10 :                         _pointerCenter->setColor(Color::Green_500);
     352          10 :                         _pointerCenter->setVisible(false);
     353          10 :                 } while (0);
     354             :         }
     355          10 : }
     356             : 
     357           0 : void Scene2d::updateInputEventData(InputEventData &data, const InputEventData &source, Vec2 sourcePosition, uint32_t id) {
     358           0 :         auto pos = _inverse.transformPoint(sourcePosition);
     359             : 
     360           0 :         data = source;
     361           0 :         data.id = id;
     362           0 :         data.x = pos.x;
     363           0 :         data.y = pos.y;
     364           0 :         data.button = InputMouseButton::Touch;
     365           0 :         data.modifiers |= InputModifier::Unmanaged;
     366           0 : }
     367             : 
     368             : }

Generated by: LCOV version 1.14