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