LCOV - code coverage report
Current view: top level - xenolith/renderer/basic2d - XL2dVectorSprite.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 144 303 47.5 %
Date: 2024-05-12 00:16:13 Functions: 17 33 51.5 %

          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 "XL2dVectorSprite.h"
      24             : #include "XLApplication.h"
      25             : #include "XLTexture.h"
      26             : #include "XL2dFrameContext.h"
      27             : #include "XLFrameInfo.h"
      28             : #include "XLDirector.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d {
      31             : 
      32       17518 : VectorSprite::VectorSprite() { }
      33             : 
      34       16158 : bool VectorSprite::init(Rc<VectorImage> &&img) {
      35       16158 :         XL_ASSERT(img, "Image should not be nullptr");
      36             : 
      37       16158 :         if (!Sprite::init() || !img) {
      38           0 :                 return false;
      39             :         }
      40             : 
      41       16158 :         _image = img;
      42       16158 :         if (_image) {
      43       16158 :                 _contentSize = _image->getImageSize();
      44             :         }
      45       16158 :         return true;
      46             : }
      47             : 
      48           0 : bool VectorSprite::init(Size2 size, StringView data) {
      49           0 :         if (!Sprite::init()) {
      50           0 :                 return false;
      51             :         }
      52             : 
      53           0 :         _image = Rc<VectorImage>::create(size, data);
      54           0 :         if (_image) {
      55           0 :                 _contentSize = _image->getImageSize();
      56             :         }
      57           0 :         return _image != nullptr;
      58             : }
      59             : 
      60           0 : bool VectorSprite::init(Size2 size, VectorPath &&path) {
      61           0 :         if (!Sprite::init()) {
      62           0 :                 return false;
      63             :         }
      64             : 
      65           0 :         _image = Rc<VectorImage>::create(size, move(path));
      66           0 :         if (_image) {
      67           0 :                 _contentSize = _image->getImageSize();
      68             :         }
      69           0 :         return _image != nullptr;
      70             : }
      71             : 
      72        1360 : bool VectorSprite::init(Size2 size) {
      73        1360 :         if (!Sprite::init()) {
      74           0 :                 return false;
      75             :         }
      76             : 
      77        1360 :         _image = Rc<VectorImage>::create(size);
      78        1360 :         if (_image) {
      79        1360 :                 _contentSize = _image->getImageSize();
      80             :         }
      81        1360 :         return _image != nullptr;
      82             : }
      83             : 
      84           0 : bool VectorSprite::init(StringView data) {
      85           0 :         if (!Sprite::init()) {
      86           0 :                 return false;
      87             :         }
      88             : 
      89           0 :         _image = Rc<VectorImage>::create(data);
      90           0 :         if (_image) {
      91           0 :                 _contentSize = _image->getImageSize();
      92             :         }
      93           0 :         return _image != nullptr;
      94             : }
      95             : 
      96           0 : bool VectorSprite::init(BytesView data) {
      97           0 :         if (!Sprite::init()) {
      98           0 :                 return false;
      99             :         }
     100             : 
     101           0 :         _image = Rc<VectorImage>::create(data);
     102           0 :         if (_image) {
     103           0 :                 _contentSize = _image->getImageSize();
     104             :         }
     105           0 :         return _image != nullptr;
     106             : }
     107             : 
     108           0 : bool VectorSprite::init(FilePath path) {
     109           0 :         if (!Sprite::init()) {
     110           0 :                 return false;
     111             :         }
     112             : 
     113           0 :         _image = Rc<VectorImage>::create(path);
     114           0 :         if (_image) {
     115           0 :                 _contentSize = _image->getImageSize();
     116             :         }
     117           0 :         return _image != nullptr;
     118             : }
     119             : 
     120           0 : Rc<VectorPathRef> VectorSprite::addPath(StringView id, StringView cache, Mat4 pos) {
     121           0 :         return _image ? _image->addPath(id, cache, pos) : nullptr;
     122             : }
     123             : 
     124           0 : Rc<VectorPathRef> VectorSprite::addPath(const VectorPath & path, StringView id, StringView cache, Mat4 pos) {
     125           0 :         return _image ? _image->addPath(path, id, cache, pos) : nullptr;
     126             : }
     127             : 
     128           0 : Rc<VectorPathRef> VectorSprite::addPath(VectorPath && path, StringView id, StringView cache, Mat4 pos) {
     129           0 :         return _image ? _image->addPath(move(path), id, cache, pos) : nullptr;
     130             : }
     131             : 
     132           0 : Rc<VectorPathRef> VectorSprite::getPath(StringView id) {
     133           0 :         return _image ? _image->getPath(id) : nullptr;
     134             : }
     135             : 
     136           0 : void VectorSprite::removePath(const Rc<VectorPathRef> &path) {
     137           0 :         if (_image) {
     138           0 :                 _image->removePath(path);
     139             :         }
     140           0 : }
     141             : 
     142           0 : void VectorSprite::removePath(StringView id) {
     143           0 :         if (_image) {
     144           0 :                 _image->removePath(id);
     145             :         }
     146           0 : }
     147             : 
     148           0 : void VectorSprite::clear() {
     149           0 :         if (_image) {
     150           0 :                 _image->clear();
     151             :         }
     152           0 : }
     153             : 
     154        2600 : void VectorSprite::setImage(Rc<VectorImage> &&img) {
     155        2600 :         if (_image != img) {
     156        2557 :                 _image = move(img);
     157        2557 :                 if (_image) {
     158        2373 :                         _image->setDirty();
     159             :                 }
     160             :         }
     161        2600 : }
     162             : 
     163           0 : const Rc<VectorImage> &VectorSprite::getImage() const {
     164           0 :         return _image;
     165             : }
     166             : 
     167         588 : void VectorSprite::setQuality(float val) {
     168         588 :         if (_quality != val) {
     169         588 :                 _quality = val;
     170         588 :                 if (_image) {
     171         588 :                         _image->setDirty();
     172             :                 }
     173             :         }
     174         588 : }
     175             : 
     176       21793 : void VectorSprite::onTransformDirty(const Mat4 &parent) {
     177       21793 :         _vertexesDirty = true;
     178       21793 :         Sprite::onTransformDirty(parent);
     179       21793 : }
     180             : 
     181       60331 : bool VectorSprite::visitDraw(FrameInfo &frame, NodeFlags parentFlags) {
     182       60331 :         if (_image && _image->isDirty()) {
     183       32781 :                 _vertexesDirty = true;
     184             :         }
     185       60331 :         return Sprite::visitDraw(frame, parentFlags);
     186             : }
     187             : 
     188           0 : uint32_t VectorSprite::getTrianglesCount() const {
     189           0 :         uint32_t ret = 0;
     190           0 :         if (_deferredResult) {
     191           0 :                 if (_deferredResult->isReady()) {
     192           0 :                         for (auto &it : _deferredResult->getResult()->data) {
     193           0 :                                 ret += it.data->indexes.size() / 3;
     194             :                         }
     195             :                 }
     196           0 :         } else if (_result) {
     197           0 :                 for (auto &it : _result->data) {
     198           0 :                         ret += it.data->indexes.size() / 3;
     199             :                 }
     200             :         }
     201           0 :         return ret;
     202             : }
     203             : 
     204           0 : uint32_t VectorSprite::getVertexesCount() const {
     205           0 :         uint32_t ret = 0;
     206           0 :         if (_deferredResult) {
     207           0 :                 if (_deferredResult->isReady()) {
     208           0 :                         for (auto &it : _deferredResult->getResult()->data) {
     209           0 :                                 ret += it.data->data.size();
     210             :                         }
     211             :                 }
     212           0 :         } else if (_result) {
     213           0 :                 for (auto &it : _result->data) {
     214           0 :                         ret += it.data->data.size();
     215             :                 }
     216             :         }
     217           0 :         return ret;
     218             : }
     219             : 
     220           0 : void VectorSprite::setDeferred(bool val) {
     221           0 :         if (val != _deferred) {
     222           0 :                 _deferred = val;
     223           0 :                 _vertexesDirty = true;
     224             :         }
     225           0 : }
     226             : 
     227        3170 : void VectorSprite::pushShadowCommands(FrameInfo &frame, NodeFlags flags, const Mat4 &transform, SpanView<TransformVertexData> data) {
     228        3170 :         FrameContextHandle2d *handle = static_cast<FrameContextHandle2d *>(frame.currentContext);
     229        3170 :         if (_deferredResult) {
     230        6340 :                 handle->shadows->pushDeferredShadow(_deferredResult, frame.viewProjectionStack.back(), transform * _targetTransform,
     231        3170 :                                 handle->getCurrentState(), _normalized, frame.depthStack.back());
     232           0 :         } else if (!data.empty()) {
     233           0 :                 auto p = new (memory::pool::palloc(frame.pool->getPool(), sizeof(TransformVertexData) * data.size())) TransformVertexData();
     234           0 :                 for (auto &it : data) {
     235           0 :                         p->transform = it.transform;
     236           0 :                         p->data = it.data;
     237           0 :                         ++ p;
     238             :                 }
     239             : 
     240           0 :                 handle->shadows->pushShadowArray(makeSpanView(p, data.size()), handle->getCurrentState(), frame.depthStack.back());
     241             :         }
     242        3170 : }
     243             : 
     244       45936 : void VectorSprite::pushCommands(FrameInfo &frame, NodeFlags flags) {
     245       45936 :         if (!_image) {
     246        1074 :                 return;
     247             :         }
     248             : 
     249       44862 :         if (!_deferredResult && (!_result || _result->data.empty())) {
     250           0 :                 return;
     251             :         }
     252             : 
     253       44862 :         FrameContextHandle2d *handle = static_cast<FrameContextHandle2d *>(frame.currentContext);
     254             : 
     255       44862 :         if (_result) {
     256           0 :                 auto &targetData = _result->mut;
     257           0 :                 auto reqMemSize = sizeof(TransformVertexData) * targetData.size();
     258             : 
     259             :                 // pool memory is 16-bytes aligned, no problems with Mat4
     260           0 :                 auto tmpData = new (memory::pool::palloc(frame.pool->getPool(), reqMemSize)) TransformVertexData[targetData.size()];
     261           0 :                 auto target = tmpData;
     262           0 :                 if (_normalized) {
     263           0 :                         auto transform = frame.modelTransformStack.back() * _targetTransform;
     264           0 :                         for (auto &it : targetData) {
     265           0 :                                 auto modelTransform = transform * it.transform;
     266             : 
     267           0 :                                 Mat4 newMV;
     268           0 :                                 newMV.m[12] = floorf(modelTransform.m[12]);
     269           0 :                                 newMV.m[13] = floorf(modelTransform.m[13]);
     270           0 :                                 newMV.m[14] = floorf(modelTransform.m[14]);
     271             : 
     272           0 :                                 target->transform = frame.viewProjectionStack.back() * newMV;
     273           0 :                                 target->data = it.data;
     274           0 :                                 ++ target;
     275             :                         }
     276             :                 } else {
     277           0 :                         auto transform = frame.viewProjectionStack.back() * frame.modelTransformStack.back() * _targetTransform;
     278           0 :                         for (auto &it : targetData) {
     279           0 :                                 auto modelTransform = transform * it.transform;
     280           0 :                                 target->transform = modelTransform;
     281           0 :                                 target->data = it.data;
     282           0 :                                 ++ target;
     283             :                         }
     284             :                 }
     285             : 
     286           0 :                 if (_depthIndex > 0.0f) {
     287           0 :                         pushShadowCommands(frame, flags, frame.modelTransformStack.back(), makeSpanView(tmpData, targetData.size()));
     288             :                 }
     289             : 
     290           0 :                 handle->commands->pushVertexArray(makeSpanView(tmpData, targetData.size()), frame.zPath,
     291           0 :                                 _materialId, handle->getCurrentState(), _realRenderingLevel, frame.depthStack.back(), _commandFlags);
     292       44862 :         } else if (_deferredResult) {
     293       44862 :                 if (_deferredResult->isReady() && _deferredResult->getResult()->data.empty()) {
     294        2935 :                         return;
     295             :                 }
     296             : 
     297       41927 :                 if (_depthIndex > 0.0f) {
     298        7861 :                         pushShadowCommands(frame, flags, frame.modelTransformStack.back());
     299             :                 }
     300             : 
     301      125781 :                 handle->commands->pushDeferredVertexResult(_deferredResult, frame.viewProjectionStack.back(),
     302       83854 :                                 frame.modelTransformStack.back() * _targetTransform, _normalized, frame.zPath,
     303       83854 :                                                 _materialId, handle->getCurrentState(), _realRenderingLevel, frame.depthStack.back(), _commandFlags);
     304             :         }
     305             : }
     306             : 
     307       17518 : void VectorSprite::initVertexes() {
     308             :         // prevent to do anything
     309       17518 : }
     310             : 
     311       22031 : static Rc<VectorCanvasDeferredResult> runDeferredVectorCavas(thread::TaskQueue &queue, Rc<VectorImageData> &&image,
     312             :                 Size2 targetSize, Color4F color, float quality, bool waitOnReady) {
     313       22031 :         auto result = new std::promise<Rc<VectorCanvasResult>>;
     314       22031 :         Rc<VectorCanvasDeferredResult> ret = Rc<VectorCanvasDeferredResult>::create(result->get_future(), waitOnReady);
     315       22031 :         queue.perform([queue = Rc<thread::TaskQueue>(&queue), image = move(image), targetSize, color, quality, ret, result] () mutable {
     316       21951 :                 auto canvas = VectorCanvas::getInstance();
     317       21965 :                 canvas->setColor(color);
     318       21960 :                 canvas->setQuality(quality);
     319       21971 :                 auto res = canvas->draw(move(image), targetSize);
     320       21969 :                 result->set_value(res);
     321             : 
     322       21932 :                 queue->onMainThread([ret = move(ret), res = move(res), result] () mutable {
     323       22031 :                         ret->handleReady(move(res));
     324       22031 :                         delete result;
     325       22031 :                 }, queue);
     326       22031 :         }, ret);
     327       22031 :         return ret;
     328           0 : }
     329             : 
     330       24181 : void VectorSprite::updateVertexes() {
     331       24181 :         if (!_image || !_director) {
     332         264 :                 return;
     333             :         }
     334             : 
     335       23917 :         Vec3 viewScale;
     336       23917 :         _modelViewTransform.decompose(&viewScale, nullptr, nullptr);
     337             : 
     338       23917 :         Size2 imageSize = _image->getImageSize();
     339       23917 :         Size2 targetViewSpaceSize(_contentSize.width * viewScale.x / _textureRect.size.width,
     340       23917 :                         _contentSize.height * viewScale.y / _textureRect.size.height);
     341             : 
     342       23917 :         float targetScaleX = _textureRect.size.width;
     343       23917 :         float targetScaleY = _textureRect.size.height;
     344       23917 :         float targetOffsetX = -_textureRect.origin.x * imageSize.width;
     345       23917 :         float targetOffsetY = -_textureRect.origin.y * imageSize.height;
     346             : 
     347       23917 :         Size2 texSize(imageSize.width * _textureRect.size.width, imageSize.height * _textureRect.size.height);
     348             : 
     349       23917 :         if (_autofit != Autofit::None) {
     350       16118 :                 float scale = 1.0f;
     351       16118 :                 switch (_autofit) {
     352           0 :                 case Autofit::None: break;
     353           0 :                 case Autofit::Width: scale = texSize.width / _contentSize.width; break;
     354           0 :                 case Autofit::Height: scale = texSize.height / _contentSize.height; break;
     355       16118 :                 case Autofit::Contain: scale = std::max(texSize.width / _contentSize.width, texSize.height / _contentSize.height); break;
     356           0 :                 case Autofit::Cover: scale = std::min(texSize.width / _contentSize.width, texSize.height / _contentSize.height); break;
     357             :                 }
     358             : 
     359       16118 :                 auto texSizeInView = Size2(texSize.width / scale, texSize.height / scale);
     360       16118 :                 targetOffsetX = targetOffsetX + (_contentSize.width - texSizeInView.width) * _autofitPos.x;
     361       16118 :                 targetOffsetY = targetOffsetY + (_contentSize.height - texSizeInView.height) * _autofitPos.y;
     362             : 
     363       32236 :                 targetViewSpaceSize = Size2(texSizeInView.width * viewScale.x,
     364       16118 :                                 texSizeInView.height * viewScale.y);
     365             : 
     366       16118 :                 targetScaleX =_textureRect.size.width;
     367       16118 :                 targetScaleY =_textureRect.size.height;
     368             :         }
     369             : 
     370             :         Mat4 targetTransform(
     371             :                 targetScaleX, 0.0f, 0.0f, targetOffsetX,
     372             :                 0.0f, targetScaleY, 0.0f, targetOffsetY,
     373             :                 0.0f, 0.0f, 1.0f, 0.0f,
     374             :                 0.0f, 0.0f, 0.0f, 1.0f
     375       23917 :         );
     376             : 
     377       23917 :         bool isDirty = false;
     378             : 
     379       23917 :         if (_targetSize != targetViewSpaceSize) {
     380       21255 :                 isDirty = true;
     381       21255 :                 _targetSize = targetViewSpaceSize;
     382             :         }
     383             : 
     384       23917 :         _targetTransform = targetTransform;
     385       23917 :         if (isDirty || _image->isDirty()) {
     386       22031 :                 _image->clearDirty();
     387             : 
     388       22031 :                 auto imageData = _image->popData();
     389             : 
     390       22031 :                 if (_deferred) {
     391       44062 :                         _deferredResult = runDeferredVectorCavas(*_director->getApplication()->getQueue(),
     392       44062 :                                         move(imageData), targetViewSpaceSize, _displayedColor, _quality, _waitDeferred);
     393       22031 :                         _result = nullptr;
     394             :                 } else {
     395           0 :                         auto canvas = VectorCanvas::getInstance();
     396           0 :                         canvas->setColor(_displayedColor);
     397           0 :                         canvas->setQuality(_quality);
     398           0 :                         _result = canvas->draw(move(imageData), targetViewSpaceSize);
     399           0 :                         _deferredResult = nullptr;
     400           0 :                 }
     401       22031 :                 _vertexColorDirty = false; // color will be already applied
     402       22031 :         }
     403             : 
     404       23917 :         Mat4 scaleTransform;
     405       23917 :         scaleTransform.scale(viewScale);
     406       23917 :         scaleTransform.inverse();
     407             : 
     408       23917 :         _targetTransform *= scaleTransform;
     409             : 
     410       23917 :         auto isSolidImage = [&, this] {
     411       45328 :                 for (auto &it : _image->getPaths()) {
     412       23799 :                         if (it.second->isAntialiased()) {
     413        2388 :                                 return false;
     414             :                         }
     415             : 
     416       21597 :                         auto s = it.second->getStyle();
     417       21597 :                         switch (s) {
     418       21597 :                         case vg::DrawStyle::Fill:
     419       21597 :                                 if (it.second->getFillOpacity() != 255) {
     420         186 :                                         return false;
     421             :                                 }
     422       21411 :                                 break;
     423           0 :                         case vg::DrawStyle::FillAndStroke:
     424           0 :                                 if (it.second->getFillOpacity() != 255) {
     425           0 :                                         return false;
     426             :                                 }
     427           0 :                                 if (it.second->getStrokeOpacity() != 255) {
     428           0 :                                         return false;
     429             :                                 }
     430           0 :                                 break;
     431           0 :                         case vg::DrawStyle::Stroke:
     432           0 :                                 if (it.second->getStrokeOpacity() != 255) {
     433           0 :                                         return false;
     434             :                                 }
     435           0 :                                 break;
     436           0 :                         default:
     437           0 :                                 break;
     438             :                         }
     439             :                 }
     440       21529 :                 return true;
     441       23917 :         };
     442             : 
     443       23917 :         auto isSolid = isSolidImage();
     444       23917 :         if (isSolid != _imageIsSolid) {
     445       16640 :                 _materialDirty = true;
     446       16640 :                 _imageIsSolid = isSolid;
     447             :         }
     448             : }
     449             : 
     450        1868 : void VectorSprite::updateVertexesColor() {
     451        1868 :         if (_deferred) {
     452        1868 :                 if (_deferredResult) {
     453        1694 :                         _deferredResult->updateColor(_displayedColor);
     454             :                 }
     455             :         } else {
     456           0 :                 if (_result) {
     457           0 :                         _result->updateColor(_displayedColor);
     458             :                 }
     459             :         }
     460        1868 : }
     461             : 
     462       52476 : RenderingLevel VectorSprite::getRealRenderingLevel() const {
     463       52476 :         auto level = _renderingLevel;
     464       52476 :         if (level == RenderingLevel::Default) {
     465       52476 :                 if (_displayedColor.a < 1.0f || !_texture || _materialInfo.getLineWidth() != 0.0f) {
     466       18092 :                         level = RenderingLevel::Transparent;
     467       34384 :                 } else if (_colorMode.getMode() == core::ColorMode::Solid) {
     468       34384 :                         if (_texture->hasAlpha()) {
     469           0 :                                 level = RenderingLevel::Transparent;
     470             :                         } else {
     471       34384 :                                 level = _imageIsSolid ? RenderingLevel::Solid : RenderingLevel::Transparent;
     472             :                         }
     473             :                 } else {
     474           0 :                         auto alphaMapping = _colorMode.getA();
     475           0 :                         switch (alphaMapping) {
     476           0 :                         case core::ComponentMapping::Identity:
     477           0 :                                 if (_texture->hasAlpha()) {
     478           0 :                                         level = RenderingLevel::Transparent;
     479             :                                 } else {
     480           0 :                                         level = _imageIsSolid ? RenderingLevel::Solid : RenderingLevel::Transparent;
     481             :                                 }
     482           0 :                                 break;
     483           0 :                         case core::ComponentMapping::Zero:
     484           0 :                                 level = RenderingLevel::Transparent;
     485           0 :                                 break;
     486           0 :                         case core::ComponentMapping::One:
     487           0 :                                 level = _imageIsSolid ? RenderingLevel::Solid : RenderingLevel::Transparent;
     488           0 :                                 break;
     489           0 :                         default:
     490           0 :                                 level = RenderingLevel::Transparent;
     491           0 :                                 break;
     492             :                         }
     493             :                 }
     494             :         }
     495       52476 :         return level;
     496             : }
     497             : 
     498             : }

Generated by: LCOV version 1.14