LCOV - code coverage report
Current view: top level - xenolith/renderer/basic2d - XL2dVectorCanvas.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 331 364 90.9 %
Date: 2024-05-12 00:16:13 Functions: 37 41 90.2 %

          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 "XL2dVectorCanvas.h"
      24             : 
      25             : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d {
      26             : 
      27             : struct VectorCanvasPathOutput {
      28             :         Color4F color;
      29             :         VertexData *vertexes = nullptr;
      30             :         uint32_t material = 0;
      31             :         uint32_t objects = 0;
      32             : };
      33             : 
      34             : struct VectorCanvasPathDrawer {
      35             :         const VectorPath *path = nullptr;
      36             : 
      37             :         bool verbose = false;
      38             :         float quality = 0.5f; // approximation level (more is better)
      39             :         Color4F originalColor;
      40             :         geom::Tesselator::RelocateRule relocateRule = geom::Tesselator::RelocateRule::Auto;
      41             : 
      42             :         uint32_t draw(memory::pool_t *pool, const VectorPath &p, const Mat4 &transform, VertexData *, bool cache);
      43             : };
      44             : 
      45             : struct VectorCanvasCacheData {
      46             :         Rc<VertexData> data;
      47             :         String name;
      48             :         float quality = 1.0f;
      49             :         float scale = 1.0f;
      50             :         vg::DrawStyle style = vg::DrawStyle::Fill;
      51             : 
      52     5188363 :         bool operator< (const VectorCanvasCacheData &other) const {
      53     5188363 :                 if (style != other.style) {
      54      342573 :                         return toInt(style) < toInt(other.style);
      55     4845790 :                 } else if (name != other.name) {
      56     4505101 :                         return name < other.name;
      57      340689 :                 } else if (quality != other.quality) {
      58           0 :                         return quality < other.quality;
      59             :                 } else {
      60      340689 :                         return scale < other.scale;
      61             :                 }
      62             :         }
      63             : };
      64             : 
      65             : struct VectorCanvasCache {
      66             :         static Mutex s_cacheMutex;
      67             :         static VectorCanvasCache *s_instance;
      68             : 
      69             :         static void retain();
      70             :         static void release();
      71             : 
      72             :         static const VectorCanvasCacheData *getCacheData(const VectorCanvasCacheData &);
      73             :         static const VectorCanvasCacheData *setCacheData(VectorCanvasCacheData &&);
      74             : 
      75             :         VectorCanvasCache();
      76             :         ~VectorCanvasCache();
      77             : 
      78             :         uint32_t refCount = 0;
      79             :         Set<VectorCanvasCacheData> cacheData;
      80             : };
      81             : 
      82             : VectorCanvasCache *VectorCanvasCache::s_instance = nullptr;
      83             : Mutex VectorCanvasCache::s_cacheMutex;
      84             : 
      85             : struct VectorCanvas::Data : memory::AllocPool {
      86             :         memory::pool_t *pool = nullptr;
      87             :         memory::pool_t *transactionPool = nullptr;
      88             :         bool isOwned = true;
      89             :         bool deferred = false;
      90             : 
      91             :         VectorCanvasPathDrawer pathDrawer;
      92             : 
      93             :         Mat4 transform = Mat4::IDENTITY;
      94             :         Vector<Mat4> states;
      95             : 
      96             :         TimeInterval subAccum;
      97             : 
      98             :         Rc<VectorImageData> image;
      99             :         Size2 targetSize;
     100             : 
     101             :         Vector<TransformVertexData> *out = nullptr;
     102             : 
     103             :         Data(memory::pool_t *p, bool deferred);
     104             :         ~Data();
     105             : 
     106             :         void save();
     107             :         void restore();
     108             : 
     109             :         void applyTransform(const Mat4 &t);
     110             : 
     111             :         void draw(const VectorPath &, StringView cache);
     112             :         void draw(const VectorPath &, StringView cache, const Mat4 &);
     113             : 
     114             :         void doDraw(const VectorPath &, StringView cache);
     115             : 
     116             :         void writeCacheData(const VectorPath &p, VertexData *out, const VertexData &source);
     117             : };
     118             : 
     119     3533958 : static void VectorCanvasPathDrawer_pushVertex(void *ptr, uint32_t idx, const Vec2 &pt, float vertexValue) {
     120     3533958 :         auto out = reinterpret_cast<VectorCanvasPathOutput *>(ptr);
     121     3533958 :         if (size_t(idx) >= out->vertexes->data.size()) {
     122           0 :                 out->vertexes->data.resize(idx + 1);
     123             :         }
     124             : 
     125     3532903 :         out->vertexes->data[idx] = Vertex{
     126     3532384 :                 Vec4(pt, 0.0f, 1.0f),
     127     3532064 :                 Vec4(out->color.r, out->color.g, out->color.b, out->color.a * vertexValue),
     128     3531834 :                 Vec2(0.0f, 0.0f), out->material, 0
     129             :         };
     130     3531834 : }
     131             : 
     132     3486873 : static void VectorCanvasPathDrawer_pushTriangle(void *ptr, uint32_t pt[3]) {
     133     3486873 :         auto out = reinterpret_cast<VectorCanvasPathOutput *>(ptr);
     134     3486873 :         out->vertexes->indexes.emplace_back(pt[0]);
     135     3487930 :         out->vertexes->indexes.emplace_back(pt[1]);
     136     3491289 :         out->vertexes->indexes.emplace_back(pt[2]);
     137     3492084 :         ++ out->objects;
     138     3492084 : }
     139             : 
     140       21950 : Rc<VectorCanvas> VectorCanvas::getInstance(bool deferred) {
     141       21950 :         static thread_local Rc<VectorCanvas> tl_instance = nullptr;
     142       21950 :         if (!tl_instance) {
     143          40 :                 tl_instance = Rc<VectorCanvas>::create(deferred);
     144             :         }
     145       21945 :         return tl_instance;
     146             : }
     147             : 
     148          93 : VectorCanvas::~VectorCanvas() {
     149          46 :         if (_data && _data->isOwned) {
     150          47 :                 auto p = _data->pool;
     151          47 :                 _data->~Data();
     152          43 :                 _data = nullptr;
     153          43 :                 memory::pool::destroy(p);
     154             :         }
     155          96 : }
     156             : 
     157          50 : bool VectorCanvas::init(bool deferred, float quality, Color4F color) {
     158          50 :         auto p = memory::pool::createTagged("xenolith::VectorCanvas");
     159          50 :         memory::pool::context ctx(p);
     160          50 :         _data = new (p) Data(p, deferred);
     161          50 :         if (_data) {
     162          50 :                 _data->pathDrawer.quality = quality;
     163          50 :                 _data->pathDrawer.originalColor = color;
     164          50 :                 return true;
     165             :         }
     166           0 :         return false;
     167          50 : }
     168             : 
     169       21958 : void VectorCanvas::setColor(Color4F color) {
     170       21958 :         _data->pathDrawer.originalColor = color;
     171       21958 : }
     172             : 
     173      192038 : Color4F VectorCanvas::getColor() const {
     174      192038 :         return _data->pathDrawer.originalColor;
     175             : }
     176             : 
     177       21970 : void VectorCanvas::setQuality(float value) {
     178       21970 :         _data->pathDrawer.quality = value;
     179       21970 : }
     180             : 
     181           0 : float VectorCanvas::getQuality() const {
     182           0 :         return _data->pathDrawer.quality;
     183             : }
     184             : 
     185          40 : void VectorCanvas::setRelocateRule(geom::Tesselator::RelocateRule rule) {
     186          40 :         _data->pathDrawer.relocateRule = rule;
     187          40 : }
     188             : 
     189           0 : geom::Tesselator::RelocateRule VectorCanvas::getRelocateRule() const {
     190           0 :         return _data->pathDrawer.relocateRule;
     191             : }
     192             : 
     193           0 : void VectorCanvas::setVerbose(bool val) {
     194           0 :         _data->pathDrawer.verbose = val;
     195           0 : }
     196             : 
     197      192060 : Rc<VectorCanvasResult> VectorCanvas::draw(Rc<VectorImageData> &&image, Size2 targetSize) {
     198      192060 :         auto ret = Rc<VectorCanvasResult>::alloc();
     199      192041 :         _data->out = &ret->data;
     200      192041 :         _data->image = move(image);
     201      192049 :         ret->targetSize = _data->targetSize = targetSize;
     202      192043 :         ret->targetColor = getColor();
     203             : 
     204      192035 :         auto imageSize = _data->image->getImageSize();
     205             : 
     206      192039 :         Mat4 t = Mat4::IDENTITY;
     207      192039 :         t.scale(targetSize.width / imageSize.width, targetSize.height / imageSize.height, 1.0f);
     208             : 
     209      192086 :         ret->targetTransform = t;
     210             : 
     211      192085 :         auto &m = _data->image->getViewBoxTransform();
     212      192076 :         if (!m.isIdentity()) {
     213           0 :                 t *= m;
     214             :         }
     215             : 
     216      192081 :         bool isIdentity = t.isIdentity();
     217             : 
     218      192073 :         if (!isIdentity) {
     219       20109 :                 _data->save();
     220       20087 :                 _data->applyTransform(t);
     221             :         }
     222             : 
     223      192045 :         _data->image->draw([&, this] (const VectorPath &path, StringView cacheId, const Mat4 &pos) {
     224      192083 :                 if (pos.isIdentity()) {
     225      192086 :                         _data->draw(path, cacheId);
     226             :                 } else {
     227           0 :                         _data->draw(path, cacheId, pos);
     228             :                 }
     229      192060 :         });
     230             : 
     231      191996 :         if (!isIdentity) {
     232       20032 :                 _data->restore();
     233             :         }
     234             : 
     235      191989 :         if (!_data->out->empty() && _data->out->back().data->data.empty()) {
     236         728 :                 _data->out->pop_back();
     237             :         }
     238             : 
     239      192005 :         _data->out = nullptr;
     240      192005 :         _data->image = nullptr;
     241      192028 :         ret->updateColor(ret->targetColor);
     242      384170 :         return ret;
     243           0 : }
     244             : 
     245          50 : VectorCanvas::Data::Data(memory::pool_t *p, bool deferred) : pool(p), deferred(deferred) {
     246          50 :         transactionPool = memory::pool::create(pool);
     247             : 
     248          50 :         VectorCanvasCache::retain();
     249          50 : }
     250             : 
     251          50 : VectorCanvas::Data::~Data() {
     252          50 :         VectorCanvasCache::release();
     253             : 
     254          50 :         memory::pool::destroy(transactionPool);
     255          49 : }
     256             : 
     257      206247 : void VectorCanvas::Data::save() {
     258      206247 :         states.push_back(transform);
     259      206229 : }
     260             : 
     261      206144 : void VectorCanvas::Data::restore() {
     262      206144 :         if (!states.empty()) {
     263      206161 :                 transform = states.back();
     264      206167 :                 states.pop_back();
     265             :         }
     266      206150 : }
     267             : 
     268      206210 : void VectorCanvas::Data::applyTransform(const Mat4 &t) {
     269      206210 :         transform *= t;
     270      206217 : }
     271             : 
     272      192085 : void VectorCanvas::Data::draw(const VectorPath &path, StringView cache) {
     273      192085 :         bool hasTransform = !path.getTransform().isIdentity();
     274      192104 :         if (hasTransform) {
     275      186165 :                 save();
     276      186155 :                 applyTransform(path.getTransform());
     277             :         }
     278             : 
     279      192088 :         doDraw(path, cache);
     280             : 
     281      192061 :         if (hasTransform) {
     282      186158 :                 restore();
     283             :         }
     284      192063 : }
     285             : 
     286           0 : void VectorCanvas::Data::draw(const VectorPath &path, StringView cache, const Mat4 &mat) {
     287           0 :         auto matTransform = path.getTransform() * mat;
     288           0 :         bool hasTransform = !matTransform.isIdentity();
     289             : 
     290           0 :         if (hasTransform) {
     291           0 :                 save();
     292           0 :                 applyTransform(path.getTransform());
     293             :         }
     294             : 
     295           0 :         doDraw(path, cache);
     296             : 
     297           0 :         if (hasTransform) {
     298           0 :                 restore();
     299             :         }
     300           0 : }
     301             : 
     302      192072 : void VectorCanvas::Data::doDraw(const VectorPath &path, StringView cache) {
     303      192072 :         VertexData *outData = nullptr;
     304      192072 :         if (out->empty() || !out->back().data->data.empty()) {
     305      192080 :                 out->emplace_back(TransformVertexData{transform, Rc<VertexData>::alloc()});
     306             :         }
     307             : 
     308      192017 :         outData = out->back().data.get();
     309      192028 :         memory::pool::push(transactionPool);
     310             : 
     311             :         do {
     312      192048 :                 if (!deferred && !cache.empty()) {
     313      170149 :                         auto style = path.getStyle();
     314      170149 :                         float quality = pathDrawer.quality;
     315             : 
     316      170149 :                         Vec3 scaleVec; transform.getScale(&scaleVec);
     317      170149 :                         float scale = std::max(scaleVec.x, scaleVec.y);
     318             : 
     319      170149 :                         VectorCanvasCacheData data{nullptr, cache.str<Interface>(), quality, scale, style};
     320             : 
     321      170148 :                         if (auto it = VectorCanvasCache::getCacheData(data)) {
     322      141827 :                                 if (!it->data->indexes.empty()) {
     323      141827 :                                         writeCacheData(path, outData, *it->data);
     324             :                                 }
     325      141827 :                                 break;
     326             :                         }
     327             : 
     328       28323 :                         data.data = Rc<VertexData>::alloc();
     329             : 
     330       28323 :                         auto ret = pathDrawer.draw(transactionPool, path, transform, data.data, true);
     331       28323 :                         if (ret != 0) {
     332       28253 :                                 if (auto it = VectorCanvasCache::setCacheData(move(data))) {
     333       28253 :                                         writeCacheData(path, outData, *it->data);
     334             :                                 }
     335             :                         } else {
     336          70 :                                 outData->data.clear();
     337          70 :                                 outData->indexes.clear();
     338          70 :                                 out->back().transform = transform;
     339             :                         }
     340      170150 :                 } else {
     341       21900 :                         auto ret = pathDrawer.draw(transactionPool, path, transform, outData, false);
     342       21922 :                         if (ret == 0) {
     343         658 :                                 outData->data.clear();
     344         658 :                                 outData->indexes.clear();
     345         657 :                                 out->back().transform = transform;
     346             :                         }
     347             :                 }
     348             :         } while (0);
     349             : 
     350      192071 :         memory::pool::pop();
     351      192082 :         memory::pool::clear(transactionPool);
     352      192066 : }
     353             : 
     354      170080 : void VectorCanvas::Data::writeCacheData(const VectorPath &p, VertexData *out, const VertexData &source) {
     355      170080 :         auto fillColor = Color4F(p.getFillColor());
     356      170080 :         auto strokeColor = Color4F(p.getStrokeColor());
     357             : 
     358      170080 :         Vec4 fillVec = fillColor;
     359      170080 :         Vec4 strokeVec = strokeColor;
     360             : 
     361      170080 :         out->indexes = source.indexes;
     362      170080 :         out->data = source.data;
     363    14972026 :         for (auto &it : out->data) {
     364    14801946 :                 if (it.material == 0) {
     365    12311056 :                         it.color = it.color * fillVec;
     366     2490890 :                 } else if (it.material == 1) {
     367     2490890 :                         it.color = it.color * strokeVec;
     368             :                 }
     369             :         }
     370      170080 : }
     371             : 
     372       50208 : uint32_t VectorCanvasPathDrawer::draw(memory::pool_t *pool, const VectorPath &p, const Mat4 &transform,
     373             :                 VertexData *out, bool cache) {
     374       50208 :         bool success = true;
     375       50208 :         path = &p;
     376             : 
     377       50208 :         float approxScale = 1.0f;
     378       50208 :         auto style = path->getStyle();
     379             : 
     380       50211 :         Rc<geom::Tesselator> strokeTess = ((style & geom::DrawStyle::Stroke) != geom::DrawStyle::None) ? Rc<geom::Tesselator>::create(pool) : nullptr;
     381       50206 :         Rc<geom::Tesselator> fillTess = ((style & geom::DrawStyle::Fill) != geom::DrawStyle::None) ? Rc<geom::Tesselator>::create(pool) : nullptr;
     382             : 
     383       50204 :         Vec3 scale; transform.getScale(&scale);
     384       50271 :         approxScale = std::max(scale.x, scale.y);
     385             : 
     386      100495 :         geom::LineDrawer line(approxScale * quality, Rc<geom::Tesselator>(fillTess), Rc<geom::Tesselator>(strokeTess),
     387      100490 :                         path->getStrokeWidth());
     388             : 
     389       50248 :         auto d = path->getPoints().data();
     390     1534492 :         for (auto &it : path->getCommands()) {
     391     1479694 :                 switch (it) {
     392      171409 :                 case vg::Command::MoveTo: line.drawBegin(d[0].p.x, d[0].p.y); ++ d; break;
     393      756369 :                 case vg::Command::LineTo: line.drawLine(d[0].p.x, d[0].p.y); ++ d; break;
     394           0 :                 case vg::Command::QuadTo: line.drawQuadBezier(d[0].p.x, d[0].p.y, d[1].p.x, d[1].p.y); d += 2; break;
     395      363411 :                 case vg::Command::CubicTo: line.drawCubicBezier(d[0].p.x, d[0].p.y, d[1].p.x, d[1].p.y, d[2].p.x, d[2].p.y); d += 3; break;
     396       24733 :                 case vg::Command::ArcTo: line.drawArc(d[0].p.x, d[0].p.y, d[2].f.v, d[2].f.a, d[2].f.b, d[1].p.x, d[1].p.y); d += 3; break;
     397      163772 :                 case vg::Command::ClosePath: line.drawClose(true); break;
     398           0 :                 default: break;
     399             :                 }
     400             :         }
     401             : 
     402       50091 :         line.drawClose(false);
     403             : 
     404       50324 :         VectorCanvasPathOutput target { Color4F::WHITE, out };
     405       50324 :         geom::TessResult result;
     406       50307 :         result.target = &target;
     407       50307 :         result.pushVertex = VectorCanvasPathDrawer_pushVertex;
     408       50307 :         result.pushTriangle = VectorCanvasPathDrawer_pushTriangle;
     409             : 
     410       50307 :         if (fillTess) {
     411             :                 // draw antialias outline only if stroke is transparent enough
     412             :                 // for cached image, always draw antialias, because user can change color and opacity
     413       21943 :                 if (path->isAntialiased() && (path->getStyle() == vg::DrawStyle::Fill || path->getStrokeOpacity() < 96 || cache)) {
     414        2253 :                         fillTess->setAntialiasValue(config::VGAntialiasFactor / approxScale);
     415        2253 :                         fillTess->setRelocateRule(relocateRule);
     416             :                 }
     417       21951 :                 fillTess->setWindingRule(path->getWindingRule());
     418       21958 :                 if (!fillTess->prepare(result)) {
     419           0 :                         success = false;
     420             :                 }
     421             :         }
     422             : 
     423       50290 :         if (strokeTess) {
     424       28360 :                 if (path->isAntialiased()) {
     425          10 :                         strokeTess->setAntialiasValue(config::VGAntialiasFactor / approxScale);
     426             :                 }
     427             : 
     428       28360 :                 strokeTess->setWindingRule(vg::Winding::NonZero);
     429       28360 :                 if (!strokeTess->prepare(result)) {
     430          70 :                         success = false;
     431             :                 }
     432             :         }
     433             : 
     434       50285 :         out->data.resize(result.nvertexes);
     435       50311 :         out->indexes.reserve(result.nfaces * 3);
     436             : 
     437       50299 :         if (fillTess) {
     438       21939 :                 target.material = 0;
     439       21939 :                 if (cache) {
     440           3 :                         target.color = Color4F::WHITE;
     441             :                 } else {
     442       21936 :                         target.color = Color4F(path->getFillColor());
     443             :                 }
     444       21932 :                 fillTess->write(result);
     445             :         }
     446             : 
     447       50336 :         if (strokeTess) {
     448       28360 :                 target.material = 1;
     449       28360 :                 if (cache) {
     450       28320 :                         target.color = Color4F::WHITE;
     451             :                 } else {
     452          40 :                         target.color = Color4F(path->getStrokeColor());
     453             :                 }
     454       28360 :                 strokeTess->write(result);
     455             :         }
     456             : 
     457       50340 :         if (!success) {
     458          70 :                 if (verbose) {
     459           0 :                         log::error("VectorCanvasPathDrawer", "Failed path:\n", path->toString(true));
     460             :                 }
     461             :         }
     462             : 
     463       50253 :         return target.objects;
     464       50340 : }
     465             : 
     466             : 
     467          50 : void VectorCanvasCache::retain() {
     468          50 :         std::unique_lock<Mutex> lock(s_cacheMutex);
     469             : 
     470          50 :         if (!s_instance) {
     471          20 :                 s_instance = new VectorCanvasCache();
     472             :         }
     473          50 :         ++ s_instance->refCount;
     474          50 : }
     475             : 
     476          45 : void VectorCanvasCache::release() {
     477          45 :         std::unique_lock<Mutex> lock(s_cacheMutex);
     478             : 
     479          50 :         if (s_instance) {
     480          50 :                 if (s_instance->refCount == 1) {
     481          20 :                         delete s_instance;
     482          20 :                         s_instance = nullptr;
     483             :                 } else {
     484          30 :                         -- s_instance->refCount;
     485             :                 }
     486             :         }
     487          50 : }
     488             : 
     489      170150 : const VectorCanvasCacheData *VectorCanvasCache::getCacheData(const VectorCanvasCacheData &data) {
     490      170150 :         std::unique_lock<Mutex> lock(s_cacheMutex);
     491      170150 :         if (!s_instance) {
     492           0 :                 return nullptr;
     493             :         }
     494             : 
     495      170150 :         auto it = s_instance->cacheData.find(data);
     496      170150 :         if (it != s_instance->cacheData.end()) {
     497      141827 :                 return &*it;
     498             :         }
     499             : 
     500       28323 :         return nullptr;
     501      170150 : }
     502             : 
     503       28253 : const VectorCanvasCacheData *VectorCanvasCache::setCacheData(VectorCanvasCacheData &&data) {
     504       28253 :         std::unique_lock<Mutex> lock(s_cacheMutex);
     505       28253 :         if (!s_instance) {
     506           0 :                 return nullptr;
     507             :         }
     508             : 
     509       28253 :         auto it = s_instance->cacheData.find(data);
     510       28253 :         if (it == s_instance->cacheData.end()) {
     511       28253 :                 it = s_instance->cacheData.emplace(move(data)).first;
     512             :         }
     513       28253 :         return &*it;
     514       28253 : }
     515             : 
     516          20 : VectorCanvasCache::VectorCanvasCache() {
     517          20 :         auto path = filesystem::writablePath<Interface>("vector_cache.cbor");
     518             : 
     519          20 :         if (filesystem::exists(path)) {
     520          20 :                 auto val = data::readFile<Interface>(path);
     521       85016 :                 for (auto &it : val.asArray()) {
     522       84996 :                         VectorCanvasCacheData data;
     523       84996 :                         data.name = it.getString("name");
     524       84996 :                         data.quality = it.getDouble("quality");
     525       84996 :                         data.scale = it.getDouble("scale");
     526             : 
     527       84996 :                         auto &vertexes = it.getBytes("vertexes");
     528       84996 :                         auto &indexes = it.getBytes("indexes");
     529             : 
     530       84996 :                         data.data = Rc<VertexData>::alloc();
     531      169992 :                         data.data->data.assign(reinterpret_cast<Vertex *>(vertexes.data()),
     532       84996 :                                         reinterpret_cast<Vertex *>(vertexes.data() + vertexes.size()));
     533      169992 :                         data.data->indexes.assign(reinterpret_cast<uint32_t *>(indexes.data()),
     534       84996 :                                         reinterpret_cast<uint32_t *>(indexes.data() + indexes.size()));
     535             : 
     536       84996 :                         cacheData.emplace(move(data));
     537       84996 :                 }
     538          20 :         }
     539          20 : }
     540             : 
     541          20 : VectorCanvasCache::~VectorCanvasCache() {
     542          20 :         Value val;
     543       85019 :         for (auto &it : cacheData) {
     544       84999 :                 if (!it.data) {
     545           0 :                         continue;
     546             :                 }
     547             : 
     548       84999 :                 Value data;
     549       84999 :                 data.setString(it.name, "name");
     550       84999 :                 data.setDouble(it.quality, "quality");
     551       84999 :                 data.setDouble(it.scale, "scale");
     552             : 
     553       84999 :                 data.setBytes(BytesView(reinterpret_cast<uint8_t *>(it.data->data.data()), it.data->data.size() * sizeof(Vertex)), "vertexes");
     554       84999 :                 data.setBytes(BytesView(reinterpret_cast<uint8_t *>(it.data->indexes.data()), it.data->indexes.size() * sizeof(uint32_t)), "indexes");
     555             : 
     556       84999 :                 val.addValue(move(data));
     557       84999 :         }
     558             : 
     559          20 :         if (!val.empty()) {
     560          20 :                 auto path = filesystem::writablePath<Interface>("vector_cache.cbor");
     561          20 :                 filesystem::mkdir(filepath::root(path));
     562             : 
     563          20 :                 filesystem::remove(path);
     564          20 :                 data::save(val, path, data::EncodeFormat::Cbor);
     565          20 :         }
     566          20 : }
     567             : 
     568      193710 : void VectorCanvasResult::updateColor(const Color4F &color) {
     569      193046 :         auto copyData = [] (const VertexData *data) {
     570      193046 :                 auto ret = Rc<VertexData>::alloc();
     571      193006 :                 ret->data.resize(data->data.size());
     572      193115 :                 ret->indexes.resize(data->indexes.size());
     573      193063 :                 memcpy(ret->data.data(), data->data.data(), data->data.size() * sizeof(Vertex));
     574      193062 :                 memcpy(ret->indexes.data(), data->indexes.data(), data->indexes.size() * sizeof(uint32_t));
     575      193041 :                 return ret;
     576           0 :         };
     577             : 
     578      193710 :         mut.clear();
     579      193701 :         mut.reserve(data.size());
     580      386393 :         for (auto &it : data) {
     581      193023 :                 auto &iit = mut.emplace_back(TransformVertexData{it.transform, copyData(it.data)});
     582    16082977 :                 for (auto &vertex : iit.data->data) {
     583    15887678 :                         vertex.color = vertex.color * color;
     584             :                 }
     585             :         }
     586             : 
     587      193776 :         targetColor = color;
     588      193776 : }
     589             : 
     590       44062 : VectorCanvasDeferredResult::~VectorCanvasDeferredResult() {
     591       22031 :         if (_future) {
     592           0 :                 delete _future;
     593           0 :                 _future = nullptr;
     594             :         }
     595       44062 : }
     596             : 
     597       22031 : bool VectorCanvasDeferredResult::init(std::future<Rc<VectorCanvasResult>> &&future, bool waitOnReady) {
     598       22031 :         _future = new std::future<Rc<VectorCanvasResult>>(move(future));
     599       22031 :         _waitOnReady = waitOnReady;
     600       22031 :         return true;
     601             : }
     602             : 
     603       29148 : SpanView<TransformVertexData> VectorCanvasDeferredResult::getData() {
     604       29148 :         std::unique_lock<Mutex> lock(_mutex);
     605       29138 :         if (_future) {
     606         326 :                 _result = _future->get();
     607         326 :                 delete _future;
     608         326 :                 _future = nullptr;
     609         326 :                 DeferredVertexResult::handleReady();
     610             :         }
     611       58234 :         return _result->mut;
     612       29114 : }
     613             : 
     614       22031 : void VectorCanvasDeferredResult::handleReady(Rc<VectorCanvasResult> &&res) {
     615       22031 :         std::unique_lock<Mutex> lock(_mutex);
     616       22031 :         if (_future) {
     617       21705 :                 delete _future;
     618       21705 :                 _future = nullptr;
     619             :         }
     620       22031 :         _result = move(res);
     621       22031 :         DeferredVertexResult::handleReady();
     622       22031 : }
     623             : 
     624       24519 : Rc<VectorCanvasResult> VectorCanvasDeferredResult::getResult() const {
     625       24519 :         std::unique_lock<Mutex> lock(_mutex);
     626       49038 :         return _result;
     627       24519 : }
     628             : 
     629        1694 : void VectorCanvasDeferredResult::updateColor(const Color4F &color) {
     630        1694 :         getResult(); // ensure rendering was complete
     631             : 
     632        1694 :         std::unique_lock<Mutex> lock(_mutex);
     633        1694 :         if (_result) {
     634        1694 :                 lock.unlock();
     635        1694 :                 _result->updateColor(color);
     636             :         }
     637        1694 : }
     638             : 
     639             : }

Generated by: LCOV version 1.14