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 = ⌖
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 : }
|