LCOV - code coverage report
Current view: top level - xenolith/renderer/material2d/base - MaterialSurface.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 159 230 69.1 %
Date: 2024-05-12 00:16:13 Functions: 20 30 66.7 %

          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 "MaterialSurface.h"
      25             : #include "MaterialEasing.h"
      26             : #include "MaterialSurfaceInterior.h"
      27             : #include "MaterialStyleContainer.h"
      28             : #include "XLFrameInfo.h"
      29             : #include "XL2dFrameContext.h"
      30             : #include "XL2dCommandList.h"
      31             : 
      32             : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
      33             : 
      34         588 : bool Surface::init(const SurfaceStyle &style) {
      35         588 :         if (!VectorSprite::init(Size2(8.0f, 8.0f))) {
      36           0 :                 return false;
      37             :         }
      38             : 
      39         588 :         _interior = addComponent(Rc<SurfaceInterior>::create());
      40             : 
      41         588 :         _styleOrigin = _styleTarget = style;
      42         588 :         _styleDirty = true;
      43             : 
      44         588 :         setQuality(QualityHigh);
      45             : 
      46         588 :         return true;
      47             : }
      48             : 
      49          56 : void Surface::setStyle(const SurfaceStyle &style) {
      50          56 :         if (_inTransition) {
      51           0 :                 _styleDirty = true;
      52           0 :                 stopAllActionsByTag(TransitionActionTag);
      53           0 :                 _inTransition = false;
      54           0 :                 _styleProgress = 0.0f;
      55             :         }
      56             : 
      57          56 :         if (_styleOrigin != style) {
      58          12 :                 _styleOrigin = _styleTarget = move(style);
      59          12 :                 _styleDirty = true;
      60             :         }
      61          56 : }
      62             : 
      63         707 : void Surface::setStyle(const SurfaceStyle &style, float duration) {
      64         707 :         if (duration <= 0.0f || !_running) {
      65          56 :                 setStyle(style);
      66          56 :                 return;
      67             :         }
      68             : 
      69         651 :         if (_inTransition || getActionByTag(TransitionActionTag)) {
      70          29 :                 _styleDirty = true;
      71          29 :                 stopAllActionsByTag(TransitionActionTag);
      72          29 :                 _inTransition = false;
      73          29 :                 _styleProgress = 0.0f;
      74             :         }
      75             : 
      76         651 :         if (_styleOrigin != style) {
      77         355 :                 _styleTarget = move(style);
      78         355 :                 runAction(makeEasing(Rc<ActionProgress>::create(duration, [this] (float progress) {
      79        2462 :                         _styleProgress = progress;
      80        2462 :                         _styleDirty = true;
      81        2817 :                 }, [this] {
      82         355 :                         _inTransition = true;
      83         700 :                 }, [this] {
      84         345 :                         _styleOrigin = _styleTarget;
      85         345 :                         _styleDirty = true;
      86         345 :                         _inTransition = false;
      87         345 :                         _styleProgress = 0.0f;
      88         345 :                 })), TransitionActionTag);
      89         355 :                 _styleDirty = true;
      90             :         }
      91             : }
      92             : 
      93           0 : void Surface::setColorRole(ColorRole value) {
      94           0 :         if (_styleTarget.colorRole != value) {
      95           0 :                 if (_styleOrigin == _styleTarget) {
      96           0 :                         _styleTarget.colorRole = _styleOrigin.colorRole = value;
      97           0 :                         _styleDirty = true;
      98             :                 } else {
      99           0 :                         _styleTarget.colorRole = value;
     100           0 :                         _styleDirty = true;
     101             :                 }
     102             :         }
     103           0 : }
     104             : 
     105           0 : void Surface::setElevation(Elevation value) {
     106           0 :         if (_styleTarget.elevation != value) {
     107           0 :                 if (_styleOrigin == _styleTarget) {
     108           0 :                         _styleTarget.elevation = _styleOrigin.elevation = value;
     109           0 :                         _styleDirty = true;
     110             :                 } else {
     111           0 :                         _styleTarget.elevation = value;
     112           0 :                         _styleDirty = true;
     113             :                 }
     114             :         }
     115           0 : }
     116             : 
     117           0 : void Surface::setShapeFamily(ShapeFamily value) {
     118           0 :         if (_styleTarget.shapeFamily != value) {
     119           0 :                 if (_styleOrigin == _styleTarget) {
     120           0 :                         _styleTarget.shapeFamily = _styleOrigin.shapeFamily = value;
     121           0 :                         _styleDirty = true;
     122             :                 } else {
     123           0 :                         _styleTarget.shapeFamily = value;
     124           0 :                         _styleDirty = true;
     125             :                 }
     126             :         }
     127           0 : }
     128             : 
     129           6 : void Surface::setShapeStyle(ShapeStyle value) {
     130           6 :         if (_styleTarget.shapeStyle != value) {
     131           6 :                 if (_styleOrigin == _styleTarget) {
     132           6 :                         _styleTarget.shapeStyle = _styleOrigin.shapeStyle = value;
     133           6 :                         _styleDirty = true;
     134             :                 } else {
     135           0 :                         _styleTarget.shapeStyle = value;
     136           0 :                         _styleDirty = true;
     137             :                 }
     138             :         }
     139           6 : }
     140             : 
     141           0 : void Surface::setNodeStyle(NodeStyle value) {
     142           0 :         if (_styleTarget.nodeStyle != value) {
     143           0 :                 if (_styleOrigin == _styleTarget) {
     144           0 :                         _styleTarget.nodeStyle = _styleOrigin.nodeStyle = value;
     145           0 :                         _styleDirty = true;
     146             :                 } else {
     147           0 :                         _styleTarget.nodeStyle = value;
     148           0 :                         _styleDirty = true;
     149             :                 }
     150             :         }
     151           0 : }
     152             : 
     153           0 : void Surface::setActivityState(ActivityState value) {
     154           0 :         if (_styleTarget.activityState != value) {
     155           0 :                 if (_styleOrigin == _styleTarget) {
     156           0 :                         _styleTarget.activityState = _styleOrigin.activityState = value;
     157           0 :                         _styleDirty = true;
     158             :                 } else {
     159           0 :                         _styleTarget.activityState = value;
     160           0 :                         _styleDirty = true;
     161             :                 }
     162             :         }
     163           0 : }
     164             : 
     165           0 : void Surface::setStyleDirtyCallback(Function<void(const SurfaceStyleData &)> &&cb) {
     166           0 :         _styleDirtyCallback = move(cb);
     167           0 :         _styleDirty = true;
     168           0 : }
     169             : 
     170       14043 : bool Surface::visitDraw(FrameInfo &frame, NodeFlags parentFlags) {
     171       14043 :         if (!_visible) {
     172        4880 :                 return false;
     173             :         }
     174             : 
     175        9163 :         auto style = getStyleContainerForFrame(frame);
     176        9163 :         if (!style) {
     177           0 :                 return false;
     178             :         }
     179             : 
     180        9163 :         if (style) {
     181        9163 :                 if (_styleTarget.apply(_styleDataTarget, _contentSize, style, getSurfaceInteriorForFrame(frame))) {
     182        1121 :                         _styleDirty = true;
     183             :                 }
     184             : 
     185        9163 :                 if (_styleOrigin.apply(_styleDataOrigin, _contentSize, style, getSurfaceInteriorForFrame(frame))) {
     186        1087 :                         _styleDirty = true;
     187             :                 }
     188             :         }
     189             : 
     190        9163 :         if (_styleDirty || _contentSizeDirty || (_image && _contentSize != _image->getImageSize())) {
     191        3014 :                 if (_styleProgress > 0.0f) {
     192        1551 :                         _styleDataCurrent = progress(_styleDataOrigin, _styleDataTarget, _styleProgress);
     193             :                 } else {
     194        1463 :                         _styleDataCurrent = _styleDataOrigin;
     195             :                 }
     196        3014 :                 applyStyle(style, _styleDataCurrent);
     197        3014 :                 _interior->setStyle(SurfaceStyleData(_styleDataCurrent));
     198             :         }
     199             : 
     200        9163 :         return VectorSprite::visitDraw(frame, parentFlags);
     201             : }
     202             : 
     203          10 : Pair<float, float> Surface::getHeightLimits(bool flex) const {
     204          10 :         return pair(_minHeight, _maxHeight);
     205             : }
     206             : 
     207           0 : void Surface::setHeightLimits(float min, float max) {
     208           0 :         _minHeight = min;
     209           0 :         _maxHeight = max;
     210           0 : }
     211             : 
     212        3014 : void Surface::applyStyle(StyleContainer *, const SurfaceStyleData &style) {
     213        3014 :         if (style.colorElevation.a == 0.0f && style.outlineValue == 0.0f) {
     214         227 :                 setImage(nullptr);
     215         227 :                 setColor(style.colorElevation, false);
     216         227 :                 setDepthIndex(style.shadowValue);
     217         227 :                 _styleDirty = false;
     218         227 :                 return;
     219             :         }
     220             : 
     221        2787 :         auto radius = std::min(std::min(_contentSize.width / 2.0f, _contentSize.height / 2.0f), style.cornerRadius);
     222             : 
     223        1909 :         if (radius != _realCornerRadius || (_image && _contentSize != _image->getImageSize()) || _outlineValue != style.outlineValue
     224        4696 :                         || _fillValue != style.colorElevation.a || style.shapeFamily != _realShapeFamily) {
     225        1201 :                 auto img = Rc<VectorImage>::create(_contentSize);
     226             : 
     227        1201 :                 updateBackgroundImage(img.get(), style, radius);
     228             : 
     229        1201 :                 _realShapeFamily = style.shapeFamily;
     230        1201 :                 _realCornerRadius = radius;
     231        1201 :                 _outlineValue = style.outlineValue;
     232        1201 :                 _fillValue = style.colorElevation.a;
     233             : 
     234        1201 :                 setImage(move(img));
     235        1201 :         }
     236             : 
     237        2787 :         if (_styleDirtyCallback) {
     238           0 :                 _styleDirtyCallback(style);
     239             :         }
     240             : 
     241        2787 :         setColor(style.colorElevation, false);
     242        2787 :         setDepthIndex(style.shadowValue);
     243        2787 :         _styleDirty = false;
     244             : }
     245             : 
     246        1201 : void Surface::updateBackgroundImage(VectorImage *img, const SurfaceStyleData &style, float radius) {
     247        1201 :         auto path = img->addPath();
     248        1201 :         if (radius > 0.0f) {
     249         640 :                 switch (style.shapeFamily) {
     250         330 :                 case ShapeFamily::RoundedCorners:
     251         330 :                         path->openForWriting([&] (vg::PathWriter &writer) {
     252         330 :                                 writer.moveTo(0.0f, radius)
     253         330 :                                         .arcTo(radius, radius, 0.0f, false, true, radius, 0.0f)
     254         330 :                                         .lineTo(_contentSize.width - radius, 0.0f)
     255         330 :                                         .arcTo(radius, radius, 0.0f, false, true, _contentSize.width, radius)
     256         330 :                                         .lineTo(_contentSize.width, _contentSize.height - radius)
     257         330 :                                         .arcTo(radius, radius, 0.0f, false, true, _contentSize.width - radius, _contentSize.height)
     258         330 :                                         .lineTo(radius, _contentSize.height)
     259         330 :                                         .arcTo(radius, radius, 0.0f, false, true, 0.0f, _contentSize.height - radius)
     260         330 :                                         .closePath();
     261         330 :                         });
     262         330 :                         break;
     263         310 :                 case ShapeFamily::CutCorners:
     264         310 :                         path->openForWriting([&] (vg::PathWriter &writer) {
     265         310 :                                 writer.moveTo(0.0f, radius)
     266         310 :                                         .lineTo(radius, 0.0f)
     267         310 :                                         .lineTo(_contentSize.width - radius, 0.0f)
     268         310 :                                         .lineTo(_contentSize.width, radius)
     269         310 :                                         .lineTo(_contentSize.width, _contentSize.height - radius)
     270         310 :                                         .lineTo(_contentSize.width - radius, _contentSize.height)
     271         310 :                                         .lineTo(radius, _contentSize.height)
     272         310 :                                         .lineTo(0.0f, _contentSize.height - radius)
     273         310 :                                         .closePath();
     274         310 :                         });
     275         310 :                         break;
     276             :                 }
     277             :         } else {
     278         561 :                 path->openForWriting([&] (vg::PathWriter &writer) {
     279         561 :                         writer.moveTo(0.0f, 0.0f)
     280         561 :                                 .lineTo(_contentSize.width, 0.0f)
     281         561 :                                 .lineTo(_contentSize.width, _contentSize.height)
     282         561 :                                 .lineTo(0.0f, _contentSize.height)
     283         561 :                                 .closePath();
     284         561 :                 });
     285             :         }
     286             : 
     287        1201 :         path->setAntialiased(false)
     288        1201 :                 .setFillColor(Color::White)
     289        1201 :                 .setFillOpacity(uint8_t(style.colorElevation.a * 255.0f))
     290        1201 :                 .setStyle(vg::DrawStyle::None);
     291             : 
     292        1201 :         if (style.colorElevation.a > 0.0f) {
     293        1201 :                 path->setStyle(path->getStyle() | vg::DrawStyle::Fill);
     294             :         }
     295             : 
     296        1201 :         if (style.outlineValue > 0.0f) {
     297           0 :                 path->setStrokeWidth(1.0f)
     298           0 :                         .setStyle(path->getStyle() | vg::DrawStyle::Stroke)
     299           0 :                         .setStrokeColor(Color::White)
     300           0 :                         .setStrokeOpacity(uint8_t(style.outlineValue * 255.0f))
     301           0 :                         .setAntialiased(true);
     302             :         }
     303        1201 : }
     304             : 
     305        9163 : StyleContainer *Surface::getStyleContainerForFrame(FrameInfo &frame) const {
     306        9163 :         return frame.getComponent<StyleContainer>(StyleContainer::ComponentFrameTag);
     307             : }
     308             : 
     309       18326 : SurfaceInterior *Surface::getSurfaceInteriorForFrame(FrameInfo &frame) const {
     310       18326 :         return frame.getComponent<SurfaceInterior>(SurfaceInterior::ComponentFrameTag);
     311             : }
     312             : 
     313        1614 : RenderingLevel Surface::getRealRenderingLevel() const {
     314        1614 :         auto l = VectorSprite::getRealRenderingLevel();
     315        1614 :         if (l == RenderingLevel::Transparent) {
     316        1352 :                 l = RenderingLevel::Surface;
     317             :         }
     318        1614 :         return l;
     319             : }
     320             : 
     321        1521 : void Surface::pushShadowCommands(FrameInfo &frame, NodeFlags flags, const Mat4 &t, SpanView<TransformVertexData> data) {
     322        1521 :         if (_realCornerRadius > 0.0f) {
     323        1171 :                 FrameContextHandle2d *handle = static_cast<FrameContextHandle2d *>(frame.currentContext);
     324        1171 :                 handle->shadows->pushSdfGroup(t, handle->getCurrentState(), frame.depthStack.back(), [&, this] (CmdSdfGroup2D &cmd) {
     325        1171 :                         switch (_realShapeFamily) {
     326         801 :                         case ShapeFamily::RoundedCorners:
     327         801 :                                 cmd.addRoundedRect2D(Rect(Vec2(0, 0), _contentSize), _realCornerRadius);
     328         801 :                                 break;
     329         370 :                         case ShapeFamily::CutCorners: {
     330             :                                 Vec2 points[8] = {
     331             :                                         Vec2(0.0f, _realCornerRadius),
     332             :                                         Vec2(_realCornerRadius, 0.0f),
     333         370 :                                         Vec2(_contentSize.width - _realCornerRadius, 0.0f),
     334             :                                         Vec2(_contentSize.width, _realCornerRadius),
     335         370 :                                         Vec2(_contentSize.width, _contentSize.height - _realCornerRadius),
     336         370 :                                         Vec2(_contentSize.width - _realCornerRadius, _contentSize.height),
     337             :                                         Vec2(_realCornerRadius, _contentSize.height),
     338         370 :                                         Vec2(0.0f, _contentSize.height - _realCornerRadius)
     339         370 :                                 };
     340         370 :                                 cmd.addPolygon2D(points);
     341         370 :                                 break;
     342             :                         }
     343             :                         }
     344        1171 :                 });
     345             :         } else {
     346         350 :                 FrameContextHandle2d *handle = static_cast<FrameContextHandle2d *>(frame.currentContext);
     347         350 :                 handle->shadows->pushSdfGroup(t, handle->getCurrentState(), frame.depthStack.back(), [&, this] (CmdSdfGroup2D &cmd) {
     348         350 :                         cmd.addRect2D(Rect(Vec2(0, 0), _contentSize));
     349         350 :                 });
     350             :         }
     351             :         //VectorSprite::pushShadowCommands(frame, flags, t, data);
     352        1521 : }
     353             : 
     354           0 : bool BackgroundSurface::init() {
     355           0 :         return init(material2d::SurfaceStyle::Background);
     356             : }
     357             : 
     358           0 : bool BackgroundSurface::init(const SurfaceStyle &style) {
     359           0 :         if (!Surface::init(style)) {
     360           0 :                 return false;
     361             :         }
     362             : 
     363           0 :         _styleContainer = addComponent(Rc<StyleContainer>::create());
     364             : 
     365           0 :         return true;
     366             : }
     367             : 
     368           0 : StyleContainer *BackgroundSurface::getStyleContainerForFrame(FrameInfo &frame) const {
     369           0 :         return _styleContainer;
     370             : }
     371             : 
     372             : }

Generated by: LCOV version 1.14