2 * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
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:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
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 THE
23 #include "tvgRender.h"
24 #include "tvgSwCommon.h"
25 #include "tvgSwRasterC.h"
26 #include "tvgSwRasterAvx.h"
27 #include "tvgSwRasterNeon.h"
29 /************************************************************************/
30 /* Internal Class Implementation */
31 /************************************************************************/
32 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
35 static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
37 return ((c * a + 0xff) >> 8);
41 static uint32_t _colorAlpha(uint32_t c)
47 static uint32_t _colorInvAlpha(uint32_t c)
53 static uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
55 return (a << 24 | b << 16 | g << 8 | r);
59 static uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
61 return (a << 24 | r << 16 | g << 8 | b);
65 static bool _translucent(const SwSurface* surface, uint8_t a)
67 if (a < 255) return true;
68 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
73 static bool _compositing(const SwSurface* surface)
75 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
80 static uint32_t _halfScale(float scale)
82 auto halfScale = static_cast<uint32_t>(0.5f / scale);
83 if (halfScale == 0) halfScale = 1;
88 //Bilinear Interpolation
89 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
91 auto rx = static_cast<uint32_t>(sx);
92 auto ry = static_cast<uint32_t>(sy);
94 auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
95 auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
97 auto c1 = img[rx + (ry * w)];
98 auto c2 = img[(rx + 1) + (ry * w)];
99 auto c3 = img[(rx + 1) + ((ry + 1) * w)];
100 auto c4 = img[rx + ((ry + 1) * w)];
102 return COLOR_INTERPOLATE(COLOR_INTERPOLATE(c1, 255 - dx, c2, dx), 255 - dy, COLOR_INTERPOLATE(c4, 255 - dx, c3, dx), dy);
106 //2n x 2n Mean Kernel
107 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n)
109 uint32_t c[4] = { 0 };
111 auto src = img + rX - n + (rY - n) * w;
112 for (auto y = rY - n; y < rY + n; ++y) {
114 for (auto x = rX - n; x < rX + n; ++x, ++p) {
116 c[1] += (*p >> 16) & 0xff;
117 c[2] += (*p >> 8) & 0xff;
122 for (auto i = 0; i < 4; ++i) {
123 c[i] = (c[i] >> 2) / n2;
125 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
129 /************************************************************************/
131 /************************************************************************/
133 static bool _rasterTranslucentMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
135 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
136 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
137 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
139 TVGLOG("SW_ENGINE", "Translucent Masked Rect");
141 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
143 for (uint32_t y = 0; y < h; ++y) {
144 auto dst = &buffer[y * surface->stride];
145 auto cmp = &cbuffer[y * surface->stride];
146 for (uint32_t x = 0; x < w; ++x) {
147 auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
148 dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp));
155 static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
157 if (surface->compositor) {
158 if (surface->compositor->method == CompositeMethod::AlphaMask) {
159 return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.alpha);
161 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
162 return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.ialpha);
166 #if defined(THORVG_AVX_VECTOR_SUPPORT)
167 return avxRasterTranslucentRect(surface, region, color);
168 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
169 return neonRasterTranslucentRect(surface, region, color);
171 return cRasterTranslucentRect(surface, region, color);
176 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
178 auto buffer = surface->buffer + (region.min.y * surface->stride);
179 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
180 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
182 for (uint32_t y = 0; y < h; ++y) {
183 rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
189 /************************************************************************/
191 /************************************************************************/
193 static bool _rasterTranslucentMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
195 TVGLOG("SW_ENGINE", "Translucent Masked Rle");
197 auto span = rle->spans;
199 auto cbuffer = surface->compositor->image.data;
201 for (uint32_t i = 0; i < rle->size; ++i) {
202 auto dst = &surface->buffer[span->y * surface->stride + span->x];
203 auto cmp = &cbuffer[span->y * surface->stride + span->x];
204 if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
206 for (uint32_t x = 0; x < span->len; ++x) {
207 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
208 dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp));
216 static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
218 if (!rle) return false;
220 if (surface->compositor) {
221 if (surface->compositor->method == CompositeMethod::AlphaMask) {
222 return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.alpha);
224 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
225 return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.ialpha);
229 #if defined(THORVG_AVX_VECTOR_SUPPORT)
230 return avxRasterTranslucentRle(surface, rle, color);
231 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
232 return neonRasterTranslucentRle(surface, rle, color);
234 return cRasterTranslucentRle(surface, rle, color);
239 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
241 if (!rle) return false;
243 auto span = rle->spans;
245 for (uint32_t i = 0; i < rle->size; ++i) {
246 if (span->coverage == 255) {
247 rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
249 auto dst = &surface->buffer[span->y * surface->stride + span->x];
250 auto src = ALPHA_BLEND(color, span->coverage);
251 auto ialpha = 255 - span->coverage;
252 for (uint32_t i = 0; i < span->len; ++i) {
253 dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
262 /************************************************************************/
263 /* RLE Transformed RGBA Image */
264 /************************************************************************/
266 static bool _rasterTransformedMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
268 TVGLOG("SW_ENGINE", "Transformed Masked Rle Image");
270 auto span = image->rle->spans;
271 auto img = image->data;
274 auto cbuffer = surface->compositor->image.data;
276 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
277 auto ey1 = span->y * itransform->e12 + itransform->e13;
278 auto ey2 = span->y * itransform->e22 + itransform->e23;
279 auto dst = &surface->buffer[span->y * surface->stride + span->x];
280 auto cmp = &cbuffer[span->y * surface->stride + span->x];
281 auto alpha = _multiplyAlpha(span->coverage, opacity);
283 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
284 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
285 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
286 if (rX >= w || rY >= h) continue;
287 auto tmp = ALPHA_BLEND(img[rY * image->stride + rX], blendMethod(*cmp));
288 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
291 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
292 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
293 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
294 if (rX >= w || rY >= h) continue;
295 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
296 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
297 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
305 static bool _rasterTransformedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity)
307 auto span = image->rle->spans;
308 auto img = image->data;
312 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
313 auto ey1 = span->y * itransform->e12 + itransform->e13;
314 auto ey2 = span->y * itransform->e22 + itransform->e23;
315 auto dst = &surface->buffer[span->y * surface->stride + span->x];
316 auto alpha = _multiplyAlpha(span->coverage, opacity);
317 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
318 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
319 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
320 if (rX >= w || rY >= h) continue;
321 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
322 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
329 static bool _rasterDownScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
331 TVGLOG("SW_ENGINE", "Down Scaled Masked Rle Image");
333 auto span = image->rle->spans;
334 auto img = image->data;
337 auto cbuffer = surface->compositor->image.data;
339 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
340 auto ey1 = span->y * itransform->e12 + itransform->e13;
341 auto ey2 = span->y * itransform->e22 + itransform->e23;
342 auto dst = &surface->buffer[span->y * surface->stride + span->x];
343 auto cmp = &cbuffer[span->y * surface->stride + span->x];
344 auto alpha = _multiplyAlpha(span->coverage, opacity);
347 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
348 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
349 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
350 if (rX >= w || rY >= h) continue;
352 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rY * image->stride + rX];
353 else src = _interpDownScaler(img, image->stride, h, rX, rY, halfScale);
354 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
355 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
358 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
359 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
360 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
361 if (rX >= w || rY >= h) continue;
363 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
364 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
365 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
366 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
374 static bool _rasterDownScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale)
376 auto span = image->rle->spans;
377 auto img = image->data;
381 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
382 auto ey1 = span->y * itransform->e12 + itransform->e13;
383 auto ey2 = span->y * itransform->e22 + itransform->e23;
384 auto dst = &surface->buffer[span->y * surface->stride + span->x];
385 auto alpha = _multiplyAlpha(span->coverage, opacity);
386 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
387 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
388 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
389 if (rX >= w || rY >= h) continue;
391 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
392 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
393 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
400 static bool _rasterUpScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
402 TVGLOG("SW_ENGINE", "Up Scaled Masked Rle Image");
404 auto span = image->rle->spans;
405 auto img = image->data;
408 auto cbuffer = surface->compositor->image.data;
410 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
411 auto ey1 = span->y * itransform->e12 + itransform->e13;
412 auto ey2 = span->y * itransform->e22 + itransform->e23;
413 auto dst = &surface->buffer[span->y * surface->stride + span->x];
414 auto cmp = &cbuffer[span->y * surface->stride + span->x];
415 auto alpha = _multiplyAlpha(span->coverage, opacity);
417 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
418 auto fX = (span->x + x) * itransform->e11 + ey1;
419 auto fY = (span->x + x) * itransform->e21 + ey2;
420 auto rX = static_cast<uint32_t>(roundf(fX));
421 auto rY = static_cast<uint32_t>(roundf(fY));
422 if (rX >= w || rY >= h) continue;
424 if (rX == w - 1 || rY == h - 1) src = img[rY * image->stride + rX];
425 else src = _interpUpScaler(img, image->stride, h, fX, fY);
426 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
427 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
430 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
431 auto fX = (span->x + x) * itransform->e11 + ey1;
432 auto fY = (span->x + x) * itransform->e21 + ey2;
433 auto rX = static_cast<uint32_t>(roundf(fX));
434 auto rY = static_cast<uint32_t>(roundf(fY));
435 if (rX >= w || rY >= h) continue;
437 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
438 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
439 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
440 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
448 static bool _rasterUpScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity)
450 auto span = image->rle->spans;
451 auto img = image->data;
455 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
456 auto ey1 = span->y * itransform->e12 + itransform->e13;
457 auto ey2 = span->y * itransform->e22 + itransform->e23;
458 auto dst = &surface->buffer[span->y * surface->stride + span->x];
459 auto alpha = _multiplyAlpha(span->coverage, opacity);
460 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
461 auto fX = (span->x + x) * itransform->e11 + ey1;
462 auto fY = (span->x + x) * itransform->e21 + ey2;
463 auto rX = static_cast<uint32_t>(roundf(fX));
464 auto rY = static_cast<uint32_t>(roundf(fY));
465 if (rX >= w || rY >= h) continue;
467 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
468 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
469 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
476 static bool _rasterTransformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
478 auto span = image->rle->spans;
480 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
481 auto ey1 = span->y * itransform->e12 + itransform->e13;
482 auto ey2 = span->y * itransform->e22 + itransform->e23;
483 auto dst = &surface->buffer[span->y * surface->stride + span->x];
485 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
486 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
487 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
488 if (rX >= image->w || rY >= image->h) continue;
489 auto src = ALPHA_BLEND(image->data[rY * image->stride + rX], span->coverage);
490 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
497 static bool _rasterDownScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale)
499 auto span = image->rle->spans;
500 auto img = image->data;
504 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
505 auto ey1 = span->y * itransform->e12 + itransform->e13;
506 auto ey2 = span->y * itransform->e22 + itransform->e23;
507 auto dst = &surface->buffer[span->y * surface->stride + span->x];
508 for (uint32_t x = span->x; x < span->len; ++x, ++dst) {
509 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
510 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
511 if (rX >= w || rY >= h) continue;
514 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
515 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage);
516 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
523 static bool _rasterUpScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
525 auto span = image->rle->spans;
526 auto img = image->data;
530 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
531 auto ey1 = span->y * itransform->e12 + itransform->e13;
532 auto ey2 = span->y * itransform->e22 + itransform->e23;
533 auto dst = &surface->buffer[span->y * surface->stride + span->x];
534 for (uint32_t x = span->x; x < span->len; ++x, ++dst) {
535 auto fX = x * itransform->e11 + ey1;
536 auto fY = x * itransform->e21 + ey2;
537 auto rX = static_cast<uint32_t>(roundf(fX));
538 auto rY = static_cast<uint32_t>(roundf(fY));
539 if (rX >= w || rY >= h) continue;
541 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
542 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage);
543 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
550 static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint32_t opacity)
552 auto halfScale = _halfScale(image->scale);
555 if (transform && !mathInverse(transform, &itransform)) return false;
557 if (_translucent(surface, opacity)) {
558 //TODO: Blenders for the following scenarios: [Opacity / Composition / Opacity + Composition]
560 if (mathEqual(image->scale, 1.0f)) {
561 if (surface->compositor) {
562 if (surface->compositor->method == CompositeMethod::AlphaMask) {
563 return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, opacity, surface->blender.alpha);
564 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
565 return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, opacity, surface->blender.ialpha);
568 return _rasterTransformedTranslucentRleRGBAImage(surface, image, &itransform, opacity);
569 //Transformed + Down Scaled
570 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
571 if (surface->compositor) {
572 if (surface->compositor->method == CompositeMethod::AlphaMask) {
573 return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, opacity, halfScale, surface->blender.alpha);
574 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
575 return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, opacity, halfScale, surface->blender.ialpha);
578 return _rasterDownScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale);
579 //Transformed + Up Scaled
581 if (surface->compositor) {
582 if (surface->compositor->method == CompositeMethod::AlphaMask) {
583 return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, opacity, surface->blender.alpha);
584 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
585 return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, opacity, surface->blender.ialpha);
588 return _rasterUpScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity);
591 //TODO: Blenders for the following scenarios: [No Composition / Composition]
592 if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRleRGBAImage(surface, image, &itransform);
593 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRleRGBAImage(surface, image, &itransform, halfScale);
594 else return _rasterUpScaledRleRGBAImage(surface, image, &itransform);
598 /************************************************************************/
599 /* RLE Scaled RGBA Image */
600 /************************************************************************/
602 static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
604 auto span = image->rle->spans;
606 //Center (Down-Scaled)
607 if (image->scale < DOWN_SCALE_TOLERANCE) {
608 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
609 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
610 if (sy >= image->h) continue;
611 auto dst = &surface->buffer[span->y * surface->stride + span->x];
612 auto cmp = &surface->compositor->image.data[span->y * surface->stride + span->x];
613 auto alpha = _multiplyAlpha(span->coverage, opacity);
615 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
616 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
617 if (sx >= image->w) continue;
618 auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
619 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
622 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
623 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
624 if (sx >= image->w) continue;
625 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
626 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
627 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
633 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
634 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
635 if (sy >= image->h) continue;
636 auto dst = &surface->buffer[span->y * surface->stride + span->x];
637 auto cmp = &surface->compositor->image.data[span->y * surface->stride + span->x];
638 auto alpha = _multiplyAlpha(span->coverage, opacity);
640 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
641 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
642 if (sx >= image->w) continue;
643 auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
644 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
647 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
648 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
649 if (sx >= image->w) continue;
650 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
651 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
652 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
661 static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
663 auto span = image->rle->spans;
665 //Center (Down-Scaled)
666 if (image->scale < DOWN_SCALE_TOLERANCE) {
667 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
668 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
669 if (sy >= image->h) continue;
670 auto dst = &surface->buffer[span->y * surface->stride + span->x];
671 auto alpha = _multiplyAlpha(span->coverage, opacity);
672 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
673 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
674 if (sx >= image->w) continue;
675 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
676 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
681 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
682 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
683 if (sy >= image->h) continue;
684 auto dst = &surface->buffer[span->y * surface->stride + span->x];
685 auto alpha = _multiplyAlpha(span->coverage, opacity);
686 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
687 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
688 if (sx >= image->w) continue;
689 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
690 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
698 static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
700 auto span = image->rle->spans;
702 //Center (Down-Scaled)
703 if (image->scale < DOWN_SCALE_TOLERANCE) {
704 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
705 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
706 if (sy >= image->h) continue;
707 auto dst = &surface->buffer[span->y * surface->stride + span->x];
708 if (span->coverage == 255) {
709 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
710 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
711 if (sx >= image->w) continue;
712 auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
713 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
716 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
717 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
718 if (sx >= image->w) continue;
719 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), span->coverage);
720 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
726 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
727 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
728 if (sy >= image->h) continue;
729 auto dst = &surface->buffer[span->y * surface->stride + span->x];
730 if (span->coverage == 255) {
731 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
732 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
733 if (sx >= image->w) continue;
734 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
735 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
738 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
739 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
740 if (sx >= image->w) continue;
741 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
742 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
751 static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
753 auto halfScale = _halfScale(image->scale);
756 if (transform && !mathInverse(transform, &itransform)) return false;
758 if (_translucent(surface, opacity)) {
759 //TODO: Blenders for the following scenarios: [Opacity / Composition / Opacity + Composition]
760 if (surface->compositor) {
761 if (surface->compositor->method == CompositeMethod::AlphaMask) {
762 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
763 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
764 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
767 return _rasterScaledTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
769 //TODO: Blenders for the following scenarios: [No Composition / Composition]
770 return _rasterScaledRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
775 /************************************************************************/
776 /* RLE Direct RGBA Image */
777 /************************************************************************/
779 static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
781 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
783 auto span = image->rle->spans;
784 auto cbuffer = surface->compositor->image.data;
786 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
787 auto dst = &surface->buffer[span->y * surface->stride + span->x];
788 auto cmp = &cbuffer[span->y * surface->stride + span->x];
789 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
790 auto alpha = _multiplyAlpha(span->coverage, opacity);
792 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
793 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
794 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
797 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
798 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
799 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
807 static bool _rasterDirectTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
809 auto span = image->rle->spans;
811 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
812 auto dst = &surface->buffer[span->y * surface->stride + span->x];
813 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
814 auto alpha = _multiplyAlpha(span->coverage, opacity);
815 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
816 auto src = ALPHA_BLEND(*img, alpha);
817 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
824 static bool _rasterDirectRleRGBAImage(SwSurface* surface, const SwImage* image)
826 auto span = image->rle->spans;
828 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
829 auto dst = &surface->buffer[span->y * surface->stride + span->x];
830 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
831 if (span->coverage == 255) {
832 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
833 *dst = *img + ALPHA_BLEND(*dst, surface->blender.ialpha(*img));
836 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
837 auto src = ALPHA_BLEND(*img, span->coverage);
838 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
846 static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
848 if (_translucent(surface, opacity)) {
849 //TODO: Blenders for the following scenarios: [Opacity / Composition / Opacity + Composition]
850 if (surface->compositor) {
851 if (surface->compositor->method == CompositeMethod::AlphaMask) {
852 return _rasterDirectMaskedRleRGBAImage(surface, image, opacity, surface->blender.alpha);
853 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
854 return _rasterDirectMaskedRleRGBAImage(surface, image, opacity, surface->blender.ialpha);
857 return _rasterDirectTranslucentRleRGBAImage(surface, image, opacity);
859 //TODO: Blenders for the following scenarios: [No Composition / Composition]
860 return _rasterDirectRleRGBAImage(surface, image);
865 /************************************************************************/
866 /* Transformed RGBA Image */
867 /************************************************************************/
869 static bool _rasterTransformedMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
871 TVGLOG("SW_ENGINE", "Transformed Masked Image");
873 auto img = image->data;
876 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
877 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
879 for (auto y = region.min.y; y < region.max.y; ++y) {
882 float ey1 = y * itransform->e12 + itransform->e13;
883 float ey2 = y * itransform->e22 + itransform->e23;
884 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
885 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
886 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
887 if (rX >= w || rY >= h) continue;
888 auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
889 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
891 dbuffer += surface->stride;
892 cbuffer += surface->stride;
898 static bool _rasterTransformedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity)
900 auto img = image->data;
903 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
905 for (auto y = region.min.y; y < region.max.y; ++y) {
907 auto ey1 = y * itransform->e12 + itransform->e13;
908 auto ey2 = y * itransform->e22 + itransform->e23;
909 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
910 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
911 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
912 if (rX >= w || rY >= h) continue;
914 auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
915 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
917 dbuffer += surface->stride;
923 static bool _rasterDownScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
925 TVGLOG("SW_ENGINE", "Down Scaled Masked Image");
927 auto img = image->data;
930 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
931 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
933 for (auto y = region.min.y; y < region.max.y; ++y) {
936 float ey1 = y * itransform->e12 + itransform->e13;
937 float ey2 = y * itransform->e22 + itransform->e23;
938 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
939 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
940 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
941 if (rX >= w || rY >= h) continue;
943 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) {
944 src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
946 src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
948 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
950 dbuffer += surface->stride;
951 cbuffer += surface->stride;
957 static bool _rasterDownScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
959 auto img = image->data;
962 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
964 for (auto y = region.min.y; y < region.max.y; ++y) {
966 auto ey1 = y * itransform->e12 + itransform->e13;
967 auto ey2 = y * itransform->e22 + itransform->e23;
968 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
969 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
970 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
971 if (rX >= w || rY >= h) continue;
973 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity);
974 else src = ALPHA_BLEND(_interpDownScaler(img, w, h, rX, rY, halfScale), opacity);
975 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
977 dbuffer += surface->stride;
983 static bool _rasterUpScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
985 TVGLOG("SW_ENGINE", "Up Scaled Masked Image");
987 auto img = image->data;
990 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
991 auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x];
993 for (auto y = region.min.y; y < region.max.y; ++y) {
996 float ey1 = y * itransform->e12 + itransform->e13;
997 float ey2 = y * itransform->e22 + itransform->e23;
998 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
999 auto fX = x * itransform->e11 + ey1;
1000 auto fY = x * itransform->e21 + ey2;
1001 auto rX = static_cast<uint32_t>(roundf(fX));
1002 auto rY = static_cast<uint32_t>(roundf(fY));
1003 if (rX >= w || rY >= h) continue;
1005 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp)));
1006 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), _multiplyAlpha(opacity, blendMethod(*cmp)));
1007 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1009 dbuffer += surface->stride;
1010 cbuffer += surface->stride;
1016 static bool _rasterUpScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity)
1018 auto img = image->data;
1021 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1023 for (auto y = region.min.y; y < region.max.y; ++y) {
1025 auto ey1 = y * itransform->e12 + itransform->e13;
1026 auto ey2 = y * itransform->e22 + itransform->e23;
1027 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1028 auto fX = x * itransform->e11 + ey1;
1029 auto fY = x * itransform->e21 + ey2;
1030 auto rX = static_cast<uint32_t>(roundf(fX));
1031 auto rY = static_cast<uint32_t>(roundf(fY));
1032 if (rX >= w || rY >= h) continue;
1034 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity);
1035 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), opacity);
1036 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1038 dbuffer += surface->stride;
1044 static bool _rasterTransformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region)
1046 auto img = image->data;
1050 for (auto y = region.min.y; y < region.max.y; ++y) {
1051 auto dst = &surface->buffer[y * surface->stride + region.min.x];
1052 auto ey1 = y * itransform->e12 + itransform->e13;
1053 auto ey2 = y * itransform->e22 + itransform->e23;
1054 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1055 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
1056 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
1057 if (rX >= w || rY >= h) continue;
1058 auto src = img[rX + (rY * image->stride)];
1059 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1066 static bool _rasterDownScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
1068 auto img = image->data;
1072 for (auto y = region.min.y; y < region.max.y; ++y) {
1073 auto dst = &surface->buffer[y * surface->stride + region.min.x];
1074 auto ey1 = y * itransform->e12 + itransform->e13;
1075 auto ey2 = y * itransform->e22 + itransform->e23;
1076 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1077 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
1078 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
1079 if (rX >= w || rY >= h) continue;
1081 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)];
1082 else src = _interpDownScaler(img, w, h, rX, rY, halfScale);
1083 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1090 static bool _rasterUpScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region)
1092 auto img = image->data;
1096 for (auto y = region.min.y; y < region.max.y; ++y) {
1097 auto dst = &surface->buffer[y * surface->stride + region.min.x];
1098 auto ey1 = y * itransform->e12 + itransform->e13;
1099 auto ey2 = y * itransform->e22 + itransform->e23;
1100 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1101 auto fX = x * itransform->e11 + ey1;
1102 auto fY = x * itransform->e21 + ey2;
1103 auto rX = static_cast<uint32_t>(roundf(fX));
1104 auto rY = static_cast<uint32_t>(roundf(fY));
1105 if (rX >= w || rY >= h) continue;
1107 if (rX == w - 1 || rY == h - 1) src = img[rX + (rY * w)];
1108 else src = _interpUpScaler(img, w, h, fX, fY);
1109 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1116 static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1118 auto halfScale = _halfScale(image->scale);
1121 if (transform && !mathInverse(transform, &itransform)) return false;
1123 if (_translucent(surface, opacity)) {
1124 //TODO: Blenders for the following scenarios: [Opacity / Composition / Opacity + Composition]
1127 if (mathEqual(image->scale, 1.0f)) {
1128 if (surface->compositor) {
1129 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1130 return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha);
1132 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1133 return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha);
1136 return _rasterTransformedTranslucentRGBAImage(surface, image, &itransform, region, opacity);
1137 //Transformed + DownScaled
1138 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
1139 if (surface->compositor) {
1140 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1141 return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
1142 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1143 return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
1146 return _rasterDownScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
1147 //Transformed + UpScaled
1149 if (surface->compositor) {
1150 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1151 return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha);
1152 }else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1153 return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha);
1156 return _rasterUpScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity);
1159 //TODO: Blenders for the following scenarios: [No Composition / Composition]
1160 if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRGBAImage(surface, image, &itransform, region);
1161 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRGBAImage(surface, image, &itransform, region, halfScale);
1162 else return _rasterUpScaledRGBAImage(surface, image, &itransform, region);
1167 /************************************************************************/
1168 /*Scaled RGBA Image */
1169 /************************************************************************/
1171 static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
1173 TVGLOG("SW_ENGINE", "Scaled Masked Image");
1176 SwCoord ys[2] = {region.min.y, region.max.y - 1};
1178 for (auto i = 0; i < 2; ++i) {
1180 auto dst = surface->buffer + (y * surface->stride + region.min.x);
1181 auto cmp = surface->compositor->image.data + (y * surface->stride + region.min.x);
1182 auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
1183 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
1184 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], _multiplyAlpha(opacity, blendMethod(*cmp)));
1185 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1189 SwCoord xs[2] = {region.min.x, region.max.x - 1};
1191 for (auto i = 0; i < 2; ++i) {
1193 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
1194 auto cmp = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + x);
1195 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1196 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride, cmp += surface->stride) {
1197 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], _multiplyAlpha(opacity, blendMethod(*cmp)));
1198 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1201 //Center (Down-Scaled)
1202 if (image->scale < DOWN_SCALE_TOLERANCE) {
1203 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1204 auto cbuffer = surface->compositor->image.data + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1205 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y) {
1208 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1209 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst, ++cmp) {
1210 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1211 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp)));
1212 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1214 dbuffer += surface->stride;
1215 cbuffer += surface->compositor->image.stride;
1217 //Center (Up-Scaled)
1219 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1220 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride + region.min.x);
1221 for (auto y = region.min.y; y < region.max.y - 1; ++y) {
1224 auto sy = y * itransform->e22 + itransform->e23;
1225 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst, ++cmp) {
1226 auto sx = x * itransform->e11 + itransform->e13;
1227 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), _multiplyAlpha(opacity, blendMethod(*cmp)));
1228 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1230 dbuffer += surface->stride;
1231 cbuffer += surface->compositor->image.stride;
1238 static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
1241 SwCoord ys[2] = {region.min.y, region.max.y - 1};
1243 for (auto i = 0; i < 2; ++i) {
1245 auto dst = surface->buffer + (y * surface->stride + region.min.x);
1246 auto img = image->data + static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride;
1247 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1248 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)], opacity);
1249 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1253 SwCoord xs[2] = {region.min.x, region.max.x - 1};
1255 for (auto i = 0; i < 2; ++i) {
1257 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
1258 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1259 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
1260 auto src = ALPHA_BLEND(img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride], opacity);
1261 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1264 //Center (Down-Scaled)
1265 if (image->scale < DOWN_SCALE_TOLERANCE) {
1266 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1267 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1268 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1270 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
1271 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1272 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity);
1273 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1276 //Center (Up-Scaled)
1278 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1279 for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1280 auto sy = y * itransform->e22 + itransform->e23;
1282 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
1283 auto sx = x * itransform->e11 + itransform->e13;
1284 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
1285 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1293 static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
1296 SwCoord ys[2] = {region.min.y, region.max.y - 1};
1298 for (auto i = 0; i < 2; ++i) {
1300 auto dst = surface->buffer + (y * surface->stride + region.min.x);
1301 auto img = image->data + static_cast<uint32_t>((y * itransform->e22 + itransform->e23)) * image->stride;
1302 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1303 auto src = img[static_cast<uint32_t>(x * itransform->e11 + itransform->e13)];
1304 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1308 SwCoord xs[2] = {region.min.x, region.max.x - 1};
1310 for (auto i = 0; i < 2; ++i) {
1312 auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x);
1313 auto img = image->data + static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1314 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) {
1315 auto src = img[static_cast<uint32_t>(y * itransform->e22 + itransform->e23) * image->stride];
1316 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1319 //Center (Down-Scaled)
1320 if (image->scale < DOWN_SCALE_TOLERANCE) {
1321 auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1));
1322 for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1323 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1325 for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) {
1326 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1327 auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
1328 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1331 //Center (Up-Scaled)
1333 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1334 for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) {
1335 auto sy = y * itransform->e22 + itransform->e23;
1337 for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) {
1338 auto sx = x * itransform->e11 + itransform->e13;
1339 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
1340 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1348 static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1350 auto halfScale = _halfScale(image->scale);
1353 if (transform && !mathInverse(transform, &itransform)) return false;
1355 if (_translucent(surface, opacity)) {
1356 //TODO: Blenders for the following scenarios: [Opacity / Composition / Opacity + Composition]
1357 if (surface->compositor) {
1358 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1359 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
1360 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1361 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
1364 return _rasterScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
1366 //TODO: Blenders for the following scenarios: [No Composition / Composition]
1367 return _rasterScaledRGBAImage(surface, image, &itransform, region, halfScale);
1372 /************************************************************************/
1373 /* Direct RGBA Image */
1374 /************************************************************************/
1376 static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
1378 TVGLOG("SW_ENGINE", "Direct Masked Image");
1380 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1381 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
1382 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
1384 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1385 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
1387 for (uint32_t y = 0; y < h2; ++y) {
1391 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
1392 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1393 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1395 buffer += surface->stride;
1396 cbuffer += surface->compositor->image.stride;
1397 sbuffer += image->stride;
1403 static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
1405 TVGLOG("SW_ENGINE", "Direct Masked Translucent Image");
1407 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1408 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
1409 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
1411 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1412 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
1414 for (uint32_t y = 0; y < h2; ++y) {
1418 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
1419 auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
1420 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1422 buffer += surface->stride;
1423 cbuffer += surface->compositor->image.stride;
1424 sbuffer += image->stride;
1430 static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1432 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1433 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1435 for (auto y = region.min.y; y < region.max.y; ++y) {
1438 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1439 auto tmp = ALPHA_BLEND(*src, opacity);
1440 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1442 dbuffer += surface->stride;
1443 sbuffer += image->stride;
1449 static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
1451 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1452 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1454 for (auto y = region.min.y; y < region.max.y; ++y) {
1457 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1458 *dst = *src + ALPHA_BLEND(*dst, surface->blender.ialpha(*src));
1460 dbuffer += surface->stride;
1461 sbuffer += image->stride;
1467 //Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
1468 static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1470 if (_compositing(surface)) {
1471 if (opacity == 255) {
1472 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1473 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.alpha);
1474 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1475 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.ialpha);
1478 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1479 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.alpha);
1480 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1481 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.ialpha);
1485 if (opacity == 255) return _rasterDirectRGBAImage(surface, image, region);
1486 else return _rasterDirectTranslucentRGBAImage(surface, image, region, opacity);
1492 //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
1493 static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1497 if (image->direct) return _directRleRGBAImage(surface, image, opacity);
1498 else if (image->scaled) return _scaledRleRGBAImage(surface, image, transform, region, opacity);
1499 //OPTIMIZE_ME: Replace with the TexMap Rasterizer
1500 else return _transformedRleRGBAImage(surface, image, transform, opacity);
1503 if (image->direct) return _directRGBAImage(surface, image, region, opacity);
1504 else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity);
1505 //OPTIMIZE_ME: Replace with the TexMap Rasterizer
1506 else return _transformedRGBAImage(surface, image, transform, region, opacity);
1511 /************************************************************************/
1512 /* Rect Linear Gradient */
1513 /************************************************************************/
1515 static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1517 if (fill->linear.len < FLT_EPSILON) return false;
1519 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1520 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1521 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1522 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1524 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1525 if (!sbuffer) return false;
1527 for (uint32_t y = 0; y < h; ++y) {
1528 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1532 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1533 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1534 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1536 buffer += surface->stride;
1537 cbuffer += surface->stride;
1543 static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1545 if (fill->linear.len < FLT_EPSILON) return false;
1547 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1548 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1549 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1551 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1552 if (!sbuffer) return false;
1555 for (uint32_t y = 0; y < h; ++y) {
1556 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1557 for (uint32_t x = 0; x < w; ++x) {
1558 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1560 dst += surface->stride;
1566 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1568 if (surface->compositor) {
1569 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1570 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1572 if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1573 return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1576 return __rasterTranslucentLinearGradientRect(surface, region, fill);
1580 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1582 if (fill->linear.len < FLT_EPSILON) return false;
1584 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1585 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1586 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1588 for (uint32_t y = 0; y < h; ++y) {
1589 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1595 /************************************************************************/
1596 /* Rle Linear Gradient */
1597 /************************************************************************/
1600 static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1602 if (fill->linear.len < FLT_EPSILON) return false;
1604 auto span = rle->spans;
1605 auto cbuffer = surface->compositor->image.data;
1606 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1607 if (!buffer) return false;
1609 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1610 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1611 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1612 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1614 if (span->coverage == 255) {
1615 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1616 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1617 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1620 auto ialpha = 255 - span->coverage;
1621 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1622 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1623 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1624 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1632 static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1634 if (fill->linear.len < FLT_EPSILON) return false;
1636 auto span = rle->spans;
1637 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1638 if (!buffer) return false;
1640 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1641 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1642 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1643 if (span->coverage == 255) {
1644 for (uint32_t i = 0; i < span->len; ++i) {
1645 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1648 for (uint32_t i = 0; i < span->len; ++i) {
1649 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1650 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1658 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1660 if (!rle) return false;
1662 if (surface->compositor) {
1663 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1664 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1665 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1666 return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1669 return __rasterTranslucentLinearGradientRle(surface, rle, fill);
1673 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1675 if (fill->linear.len < FLT_EPSILON) return false;
1677 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1678 if (!buf) return false;
1680 auto span = rle->spans;
1682 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1683 if (span->coverage == 255) {
1684 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1686 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1687 auto ialpha = 255 - span->coverage;
1688 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1689 for (uint32_t i = 0; i < span->len; ++i) {
1690 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1698 /************************************************************************/
1699 /* Rect Radial Gradient */
1700 /************************************************************************/
1702 static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1704 if (fill->radial.a < FLT_EPSILON) return false;
1706 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1707 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1708 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1709 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
1711 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1712 if (!sbuffer) return false;
1714 for (uint32_t y = 0; y < h; ++y) {
1715 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1719 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1720 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1721 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1723 buffer += surface->stride;
1724 cbuffer += surface->stride;
1730 static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1732 if (fill->radial.a < FLT_EPSILON) return false;
1734 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1735 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1736 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1738 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1739 if (!sbuffer) return false;
1742 for (uint32_t y = 0; y < h; ++y) {
1743 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1744 for (uint32_t x = 0; x < w; ++x) {
1745 dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x]));
1747 dst += surface->stride;
1753 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1755 if (surface->compositor) {
1756 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1757 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1758 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1759 return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1762 return __rasterTranslucentRadialGradientRect(surface, region, fill);
1766 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1768 if (fill->radial.a < FLT_EPSILON) return false;
1770 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1771 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1772 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1774 for (uint32_t y = 0; y < h; ++y) {
1775 auto dst = &buffer[y * surface->stride];
1776 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1782 /************************************************************************/
1783 /* RLE Radial Gradient */
1784 /************************************************************************/
1787 static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1789 if (fill->radial.a < FLT_EPSILON) return false;
1791 auto span = rle->spans;
1792 auto cbuffer = surface->compositor->image.data;
1793 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1794 if (!buffer) return false;
1796 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1797 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1798 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1799 auto cmp = &cbuffer[span->y * surface->stride + span->x];
1801 if (span->coverage == 255) {
1802 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1803 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1804 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1807 auto ialpha = 255 - span->coverage;
1808 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1809 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1810 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1811 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1819 static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1821 if (fill->radial.a < FLT_EPSILON) return false;
1823 auto span = rle->spans;
1824 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1825 if (!buffer) return false;
1827 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1828 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1829 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1830 if (span->coverage == 255) {
1831 for (uint32_t i = 0; i < span->len; ++i) {
1832 dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i]));
1835 for (uint32_t i = 0; i < span->len; ++i) {
1836 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1837 dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp));
1845 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1847 if (!rle) return false;
1849 if (surface->compositor) {
1850 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1851 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1852 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1853 return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1856 return __rasterTranslucentRadialGradientRle(surface, rle, fill);
1860 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1862 if (fill->radial.a < FLT_EPSILON) return false;
1864 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1865 if (!buf) return false;
1867 auto span = rle->spans;
1869 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1870 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1871 if (span->coverage == 255) {
1872 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1874 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1875 auto ialpha = 255 - span->coverage;
1876 for (uint32_t i = 0; i < span->len; ++i) {
1877 dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
1885 /************************************************************************/
1886 /* External Class Implementation */
1887 /************************************************************************/
1889 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1891 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1892 avxRasterRGBA32(dst, val, offset, len);
1893 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1894 neonRasterRGBA32(dst, val, offset, len);
1896 cRasterRGBA32(dst, val, offset, len);
1901 bool rasterCompositor(SwSurface* surface)
1903 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1904 surface->blender.join = _abgrJoin;
1905 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1906 surface->blender.join = _argbJoin;
1908 //What Color Space ???
1911 surface->blender.alpha = _colorAlpha;
1912 surface->blender.ialpha = _colorInvAlpha;
1918 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1920 if (!shape->fill) return false;
1922 auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1925 if (shape->fastTrack) {
1926 if (id == TVG_CLASS_ID_LINEAR) {
1927 if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
1928 return _rasterSolidLinearGradientRect(surface, shape->bbox, shape->fill);
1930 if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
1931 return _rasterSolidRadialGradientRect(surface, shape->bbox, shape->fill);
1934 if (!shape->rle) return false;
1935 if (id == TVG_CLASS_ID_LINEAR) {
1936 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
1937 return _rasterSolidLinearGradientRle(surface, shape->rle, shape->fill);
1939 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
1940 return _rasterSolidRadialGradientRle(surface, shape->rle, shape->fill);
1947 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1950 r = _multiplyAlpha(r, a);
1951 g = _multiplyAlpha(g, a);
1952 b = _multiplyAlpha(b, a);
1955 auto color = surface->blender.join(r, g, b, a);
1956 auto translucent = _translucent(surface, a);
1959 if (shape->fastTrack) {
1960 if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color);
1961 return _rasterSolidRect(surface, shape->bbox, color);
1964 return _rasterTranslucentRle(surface, shape->rle, color);
1966 return _rasterSolidRle(surface, shape->rle, color);
1970 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1973 r = _multiplyAlpha(r, a);
1974 g = _multiplyAlpha(g, a);
1975 b = _multiplyAlpha(b, a);
1978 auto color = surface->blender.join(r, g, b, a);
1979 auto translucent = _translucent(surface, a);
1981 if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
1982 return _rasterSolidRle(surface, shape->strokeRle, color);
1986 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1988 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1990 auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
1992 if (id == TVG_CLASS_ID_LINEAR) {
1993 if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1994 return _rasterSolidLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1996 if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1997 return _rasterSolidRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
2004 bool rasterClear(SwSurface* surface)
2006 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
2008 if (surface->w == surface->stride) {
2009 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
2011 for (uint32_t i = 0; i < surface->h; i++) {
2012 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
2019 void rasterUnpremultiply(SwSurface* surface)
2021 //TODO: Create simd avx and neon version
2022 for (uint32_t y = 0; y < surface->h; y++) {
2023 auto buffer = surface->buffer + surface->stride * y;
2024 for (uint32_t x = 0; x < surface->w; ++x) {
2025 uint8_t a = buffer[x] >> 24;
2028 } else if (a == 0) {
2029 buffer[x] = 0x00ffffff;
2031 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
2032 uint16_t g = ((buffer[x]) & 0xff00) / a;
2033 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
2034 if (r > 0xff) r = 0xff;
2035 if (g > 0xff) g = 0xff;
2036 if (b > 0xff) b = 0xff;
2037 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
2044 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
2047 if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= surface->w || bbox.min.y >= surface->h) return false;
2049 //TOOD: switch (image->format)
2050 //TODO: case: _rasterRGBImage()
2051 //TODO: case: _rasterGrayscaleImage()
2052 //TODO: case: _rasterAlphaImage()
2054 return _rasterRGBAImage(surface, image, transform, bbox, opacity);