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"
26 /************************************************************************/
27 /* Internal Class Implementation */
28 /************************************************************************/
29 constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
32 static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a)
34 return ((c * a + 0xff) >> 8);
38 static inline uint32_t _colorAlpha(uint32_t c)
44 static inline uint32_t _colorInvAlpha(uint32_t c)
50 static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
52 return (a << 24 | b << 16 | g << 8 | r);
56 static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
58 return (a << 24 | r << 16 | g << 8 | b);
62 #include "tvgSwRasterTexmap.h"
63 #include "tvgSwRasterC.h"
64 #include "tvgSwRasterAvx.h"
65 #include "tvgSwRasterNeon.h"
68 static inline bool _compositing(const SwSurface* surface)
70 if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false;
75 static inline uint32_t _halfScale(float scale)
77 auto halfScale = static_cast<uint32_t>(0.5f / scale);
78 if (halfScale == 0) halfScale = 1;
82 //Bilinear Interpolation
83 static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy)
85 auto rx = static_cast<uint32_t>(sx);
86 auto ry = static_cast<uint32_t>(sy);
88 if (rx2 >= w) rx2 = w - 1;
90 if (ry2 >= h) ry2 = h - 1;
92 auto dx = static_cast<uint32_t>((sx - rx) * 255.0f);
93 auto dy = static_cast<uint32_t>((sy - ry) * 255.0f);
95 auto c1 = img[rx + ry * w];
96 auto c2 = img[rx2 + ry * w];
97 auto c3 = img[rx2 + ry2 * w];
98 auto c4 = img[rx + ry2 * w];
100 return INTERPOLATE(dy, INTERPOLATE(dx, c3, c4), INTERPOLATE(dx, c2, c1));
104 //2n x 2n Mean Kernel
105 static uint32_t _interpDownScaler(const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n)
107 uint32_t c[4] = { 0 };
109 auto src = img + rX - n + (rY - n) * w;
110 for (auto y = rY - n; y < rY + n; ++y) {
112 for (auto x = rX - n; x < rX + n; ++x, ++p) {
114 c[1] += (*p >> 16) & 0xff;
115 c[2] += (*p >> 8) & 0xff;
120 for (auto i = 0; i < 4; ++i) {
121 c[i] = (c[i] >> 2) / n2;
123 return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
127 /************************************************************************/
129 /************************************************************************/
131 static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t))
133 TVGLOG("SW_ENGINE", "Masked Rect");
135 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
136 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
137 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
139 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
141 for (uint32_t y = 0; y < h; ++y) {
142 auto dst = &buffer[y * surface->stride];
143 auto cmp = &cbuffer[y * surface->stride];
144 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) {
145 auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
146 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
153 static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
155 auto buffer = surface->buffer + (region.min.y * surface->stride);
156 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
157 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
159 for (uint32_t y = 0; y < h; ++y) {
160 rasterRGBA32(buffer + y * surface->stride, color, region.min.x, w);
166 static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint8_t opacity)
168 if (_compositing(surface)) {
169 if (surface->compositor->method == CompositeMethod::AlphaMask) {
170 return _rasterMaskedRect(surface, region, color, surface->blender.alpha);
171 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
172 return _rasterMaskedRect(surface, region, color, surface->blender.ialpha);
175 if (opacity == 255) {
176 return _rasterSolidRect(surface, region, color);
178 #if defined(THORVG_AVX_VECTOR_SUPPORT)
179 return avxRasterTranslucentRect(surface, region, color);
180 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
181 return neonRasterTranslucentRect(surface, region, color);
183 return cRasterTranslucentRect(surface, region, color);
191 /************************************************************************/
193 /************************************************************************/
195 static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t))
197 TVGLOG("SW_ENGINE", "Masked Rle");
199 auto span = rle->spans;
201 auto cbuffer = surface->compositor->image.data;
203 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
204 auto dst = &surface->buffer[span->y * surface->stride + span->x];
205 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
206 if (span->coverage == 255) src = color;
207 else src = ALPHA_BLEND(color, span->coverage);
208 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
209 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
210 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
217 static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color)
219 auto span = rle->spans;
221 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
222 if (span->coverage == 255) {
223 rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len);
225 auto dst = &surface->buffer[span->y * surface->stride + span->x];
226 auto src = ALPHA_BLEND(color, span->coverage);
227 auto ialpha = 255 - span->coverage;
228 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
229 *dst = src + ALPHA_BLEND(*dst, ialpha);
237 static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8_t opacity)
239 if (!rle) return false;
241 if (_compositing(surface)) {
242 if (surface->compositor->method == CompositeMethod::AlphaMask) {
243 return _rasterMaskedRle(surface, rle, color, surface->blender.alpha);
244 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
245 return _rasterMaskedRle(surface, rle, color, surface->blender.ialpha);
248 if (opacity == 255) {
249 return _rasterSolidRle(surface, rle, color);
251 #if defined(THORVG_AVX_VECTOR_SUPPORT)
252 return avxRasterTranslucentRle(surface, rle, color);
253 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
254 return neonRasterTranslucentRle(surface, rle, color);
256 return cRasterTranslucentRle(surface, rle, color);
264 /************************************************************************/
265 /* RLE Transformed RGBA Image */
266 /************************************************************************/
268 static bool _rasterTransformedMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
270 TVGLOG("SW_ENGINE", "Transformed Masked Translucent Rle Image");
272 auto span = image->rle->spans;
273 auto img = image->data;
276 auto cbuffer = surface->compositor->image.data;
278 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
279 auto ey1 = span->y * itransform->e12 + itransform->e13;
280 auto ey2 = span->y * itransform->e22 + itransform->e23;
281 auto dst = &surface->buffer[span->y * surface->stride + span->x];
282 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
283 auto alpha = _multiplyAlpha(span->coverage, opacity);
284 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
285 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
286 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
287 if (rX >= w || rY >= h) continue;
288 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
289 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
290 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
297 static bool _rasterTransformedMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
299 TVGLOG("SW_ENGINE", "Transformed Masked Rle Image");
301 auto span = image->rle->spans;
302 auto img = image->data;
305 auto cbuffer = surface->compositor->image.data;
307 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
308 auto ey1 = span->y * itransform->e12 + itransform->e13;
309 auto ey2 = span->y * itransform->e22 + itransform->e23;
310 auto dst = &surface->buffer[span->y * surface->stride + span->x];
311 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
312 if (span->coverage == 255) {
313 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
314 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
315 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
316 if (rX >= w || rY >= h) continue;
317 auto tmp = ALPHA_BLEND(img[rY * image->stride + rX], blendMethod(*cmp));
318 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
321 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
322 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
323 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
324 if (rX >= w || rY >= h) continue;
325 auto src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
326 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
327 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
335 static bool _rasterTransformedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity)
337 auto span = image->rle->spans;
338 auto img = image->data;
342 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
343 auto ey1 = span->y * itransform->e12 + itransform->e13;
344 auto ey2 = span->y * itransform->e22 + itransform->e23;
345 auto dst = &surface->buffer[span->y * surface->stride + span->x];
346 auto alpha = _multiplyAlpha(span->coverage, opacity);
347 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
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;
351 auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
352 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
359 static bool _rasterDownScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
361 TVGLOG("SW_ENGINE", "Down Scaled Masked Translucent Rle Image");
363 auto span = image->rle->spans;
364 auto img = image->data;
367 auto cbuffer = surface->compositor->image.data;
369 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
370 auto ey1 = span->y * itransform->e12 + itransform->e13;
371 auto ey2 = span->y * itransform->e22 + itransform->e23;
372 auto dst = &surface->buffer[span->y * surface->stride + span->x];
373 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
374 auto alpha = _multiplyAlpha(span->coverage, opacity);
375 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
376 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
377 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
378 if (rX >= w || rY >= h) continue;
380 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
381 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
382 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
383 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
390 static bool _rasterDownScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
392 TVGLOG("SW_ENGINE", "Down Scaled Masked Rle Image");
394 auto span = image->rle->spans;
395 auto img = image->data;
398 auto cbuffer = surface->compositor->image.data;
400 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
401 auto ey1 = span->y * itransform->e12 + itransform->e13;
402 auto ey2 = span->y * itransform->e22 + itransform->e23;
403 auto dst = &surface->buffer[span->y * surface->stride + span->x];
404 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
405 if (span->coverage == 255) {
406 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
407 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
408 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
409 if (rX >= w || rY >= h) continue;
411 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rY * image->stride + rX];
412 else src = _interpDownScaler(img, image->stride, h, rX, rY, halfScale);
413 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
414 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
417 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
418 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
419 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
420 if (rX >= w || rY >= h) continue;
422 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
423 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage);
424 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
425 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
433 static bool _rasterDownScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale)
435 auto span = image->rle->spans;
436 auto img = image->data;
440 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
441 auto ey1 = span->y * itransform->e12 + itransform->e13;
442 auto ey2 = span->y * itransform->e22 + itransform->e23;
443 auto dst = &surface->buffer[span->y * surface->stride + span->x];
444 auto alpha = _multiplyAlpha(span->coverage, opacity);
445 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
446 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
447 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
448 if (rX >= w || rY >= h) continue;
450 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
451 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha);
452 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
459 static bool _rasterUpScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
461 TVGLOG("SW_ENGINE", "Up Scaled Masked Translucent Rle Image");
463 auto span = image->rle->spans;
464 auto img = image->data;
467 auto cbuffer = surface->compositor->image.data;
469 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
470 auto ey1 = span->y * itransform->e12 + itransform->e13;
471 auto ey2 = span->y * itransform->e22 + itransform->e23;
472 auto dst = &surface->buffer[span->y * surface->stride + span->x];
473 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
474 auto alpha = _multiplyAlpha(span->coverage, opacity);
475 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
476 auto fX = (span->x + x) * itransform->e11 + ey1;
477 auto fY = (span->x + x) * itransform->e21 + ey2;
478 auto rX = static_cast<uint32_t>(roundf(fX));
479 auto rY = static_cast<uint32_t>(roundf(fY));
480 if (rX >= w || rY >= h) continue;
482 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
483 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
484 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp)));
485 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
492 static bool _rasterUpScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t))
494 TVGLOG("SW_ENGINE", "Up Scaled Masked Rle Image");
496 auto span = image->rle->spans;
497 auto img = image->data;
500 auto cbuffer = surface->compositor->image.data;
502 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
503 auto ey1 = span->y * itransform->e12 + itransform->e13;
504 auto ey2 = span->y * itransform->e22 + itransform->e23;
505 auto dst = &surface->buffer[span->y * surface->stride + span->x];
506 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
507 if (span->coverage == 255) {
508 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
509 auto fX = (span->x + x) * itransform->e11 + ey1;
510 auto fY = (span->x + x) * itransform->e21 + ey2;
511 auto rX = static_cast<uint32_t>(roundf(fX));
512 auto rY = static_cast<uint32_t>(roundf(fY));
513 if (rX >= w || rY >= h) continue;
515 if (rX == w - 1 || rY == h - 1) src = img[rY * image->stride + rX];
516 else src = _interpUpScaler(img, image->stride, h, fX, fY);
517 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
518 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
521 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) {
522 auto fX = (span->x + x) * itransform->e11 + ey1;
523 auto fY = (span->x + x) * itransform->e21 + ey2;
524 auto rX = static_cast<uint32_t>(roundf(fX));
525 auto rY = static_cast<uint32_t>(roundf(fY));
526 if (rX >= w || rY >= h) continue;
528 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
529 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage);
530 auto tmp = ALPHA_BLEND(src, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
531 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
539 static bool _rasterUpScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity)
541 auto span = image->rle->spans;
542 auto img = image->data;
546 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
547 auto ey1 = span->y * itransform->e12 + itransform->e13;
548 auto ey2 = span->y * itransform->e22 + itransform->e23;
549 auto dst = &surface->buffer[span->y * surface->stride + span->x];
550 auto alpha = _multiplyAlpha(span->coverage, opacity);
551 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
552 auto fX = (span->x + x) * itransform->e11 + ey1;
553 auto fY = (span->x + x) * itransform->e21 + ey2;
554 auto rX = static_cast<uint32_t>(roundf(fX));
555 auto rY = static_cast<uint32_t>(roundf(fY));
556 if (rX >= w || rY >= h) continue;
558 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha);
559 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha);
560 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
567 static bool _rasterTransformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
569 auto span = image->rle->spans;
571 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
572 auto ey1 = span->y * itransform->e12 + itransform->e13;
573 auto ey2 = span->y * itransform->e22 + itransform->e23;
574 auto dst = &surface->buffer[span->y * surface->stride + span->x];
576 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
577 auto rX = static_cast<uint32_t>(roundf((span->x + x) * itransform->e11 + ey1));
578 auto rY = static_cast<uint32_t>(roundf((span->x + x) * itransform->e21 + ey2));
579 if (rX >= image->w || rY >= image->h) continue;
580 auto src = ALPHA_BLEND(image->data[rY * image->stride + rX], span->coverage);
581 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
588 static bool _rasterDownScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale)
590 auto span = image->rle->spans;
591 auto img = image->data;
595 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
596 auto ey1 = span->y * itransform->e12 + itransform->e13;
597 auto ey2 = span->y * itransform->e22 + itransform->e23;
598 auto dst = &surface->buffer[span->y * surface->stride + span->x];
599 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
600 auto rX = static_cast<uint32_t>(roundf(x * itransform->e11 + ey1));
601 auto rY = static_cast<uint32_t>(roundf(x * itransform->e21 + ey2));
602 if (rX >= w || rY >= h) continue;
605 if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
606 else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage);
607 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
614 static bool _rasterUpScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform)
616 auto span = image->rle->spans;
617 auto img = image->data;
621 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
622 auto ey1 = span->y * itransform->e12 + itransform->e13;
623 auto ey2 = span->y * itransform->e22 + itransform->e23;
624 auto dst = &surface->buffer[span->y * surface->stride + span->x];
625 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
626 auto fX = x * itransform->e11 + ey1;
627 auto fY = x * itransform->e21 + ey2;
628 auto rX = static_cast<uint32_t>(roundf(fX));
629 auto rY = static_cast<uint32_t>(roundf(fY));
630 if (rX >= w || rY >= h) continue;
632 if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage);
633 else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage);
634 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
641 static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint32_t opacity)
644 mathIdentity(&itransform);
645 if (transform && !mathInverse(transform, &itransform)) return false;
647 auto halfScale = _halfScale(image->scale);
649 if (_compositing(surface)) {
650 if (opacity == 255) {
652 if (mathEqual(image->scale, 1.0f)) {
653 if (surface->compositor->method == CompositeMethod::AlphaMask) {
654 return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, surface->blender.alpha);
655 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
656 return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, surface->blender.ialpha);
658 //Transformed + Down Scaled
659 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
660 if (surface->compositor->method == CompositeMethod::AlphaMask) {
661 return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, halfScale, surface->blender.alpha);
662 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
663 return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, halfScale, surface->blender.ialpha);
665 //Transformed + Up Scaled
667 if (surface->compositor->method == CompositeMethod::AlphaMask) {
668 return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, surface->blender.alpha);
669 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
670 return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, surface->blender.ialpha);
675 if (mathEqual(image->scale, 1.0f)) {
676 if (surface->compositor->method == CompositeMethod::AlphaMask) {
677 return _rasterTransformedMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, surface->blender.alpha);
678 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
679 return _rasterTransformedMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, surface->blender.ialpha);
681 //Transformed + Down Scaled
682 } else if (image->scale < DOWN_SCALE_TOLERANCE) {
683 if (surface->compositor->method == CompositeMethod::AlphaMask) {
684 return _rasterDownScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale, surface->blender.alpha);
685 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
686 return _rasterDownScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale, surface->blender.ialpha);
688 //Transformed + Up Scaled
690 if (surface->compositor->method == CompositeMethod::AlphaMask) {
691 return _rasterUpScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, surface->blender.alpha);
692 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
693 return _rasterUpScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, surface->blender.ialpha);
698 if (opacity == 255) {
699 if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRleRGBAImage(surface, image, &itransform);
700 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRleRGBAImage(surface, image, &itransform, halfScale);
701 else return _rasterUpScaledRleRGBAImage(surface, image, &itransform);
703 if (mathEqual(image->scale, 1.0f)) return _rasterTransformedTranslucentRleRGBAImage(surface, image, &itransform, opacity);
704 else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale);
705 else return _rasterUpScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity);
711 /************************************************************************/
712 /* RLE Scaled RGBA Image */
713 /************************************************************************/
715 static bool _rasterScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
717 TVGLOG("SW_ENGINE", "Scaled Masked Translucent Rle Image");
719 auto span = image->rle->spans;
721 //Center (Down-Scaled)
722 if (image->scale < DOWN_SCALE_TOLERANCE) {
723 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
724 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
725 if (sy >= image->h) continue;
726 auto dst = &surface->buffer[span->y * surface->stride + span->x];
727 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
728 auto alpha = _multiplyAlpha(span->coverage, opacity);
729 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
730 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
731 if (sx >= image->w) continue;
732 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
733 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
734 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
739 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
740 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
741 if (sy >= image->h) continue;
742 auto dst = &surface->buffer[span->y * surface->stride + span->x];
743 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
744 auto alpha = _multiplyAlpha(span->coverage, opacity);
745 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
746 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
747 if (sx >= image->w) continue;
748 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
749 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
750 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
758 static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
760 TVGLOG("SW_ENGINE", "Scaled Masked Rle Image");
762 auto span = image->rle->spans;
764 //Center (Down-Scaled)
765 if (image->scale < DOWN_SCALE_TOLERANCE) {
766 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
767 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
768 if (sy >= image->h) continue;
769 auto dst = &surface->buffer[span->y * surface->stride + span->x];
770 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
771 if (span->coverage == 255) {
772 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
773 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
774 if (sx >= image->w) continue;
775 auto tmp = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
776 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
779 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
780 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
781 if (sx >= image->w) continue;
782 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), span->coverage);
783 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
784 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
790 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
791 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
792 if (sy >= image->h) continue;
793 auto dst = &surface->buffer[span->y * surface->stride + span->x];
794 auto cmp = &surface->compositor->image.data[span->y * surface->compositor->image.stride + span->x];
795 if (span->coverage == 255) {
796 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
797 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
798 if (sx >= image->w) continue;
799 auto tmp = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
800 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
803 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst, ++cmp) {
804 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
805 if (sx >= image->w) continue;
806 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
807 auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
808 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
817 static bool _rasterScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
819 auto span = image->rle->spans;
821 //Center (Down-Scaled)
822 if (image->scale < DOWN_SCALE_TOLERANCE) {
823 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
824 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
825 if (sy >= image->h) continue;
826 auto dst = &surface->buffer[span->y * surface->stride + span->x];
827 auto alpha = _multiplyAlpha(span->coverage, opacity);
828 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
829 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
830 if (sx >= image->w) continue;
831 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
832 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
837 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
838 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
839 if (sy >= image->h) continue;
840 auto dst = &surface->buffer[span->y * surface->stride + span->x];
841 auto alpha = _multiplyAlpha(span->coverage, opacity);
842 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
843 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
844 if (sx >= image->w) continue;
845 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
846 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
854 static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
856 auto span = image->rle->spans;
858 //Center (Down-Scaled)
859 if (image->scale < DOWN_SCALE_TOLERANCE) {
860 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
861 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
862 if (sy >= image->h) continue;
863 auto dst = &surface->buffer[span->y * surface->stride + span->x];
864 if (span->coverage == 255) {
865 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
866 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
867 if (sx >= image->w) continue;
868 auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
869 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
872 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
873 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
874 if (sx >= image->w) continue;
875 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), span->coverage);
876 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
882 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
883 auto sy = static_cast<uint32_t>(span->y * itransform->e22 + itransform->e23);
884 if (sy >= image->h) continue;
885 auto dst = &surface->buffer[span->y * surface->stride + span->x];
886 if (span->coverage == 255) {
887 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
888 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
889 if (sx >= image->w) continue;
890 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
891 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
894 for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) {
895 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
896 if (sx >= image->w) continue;
897 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), span->coverage);
898 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
907 static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
910 if (transform && !mathInverse(transform, &itransform)) return false;
912 auto halfScale = _halfScale(image->scale);
914 if (_compositing(surface)) {
915 if (opacity == 255) {
916 if (surface->compositor->method == CompositeMethod::AlphaMask) {
917 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.alpha);
918 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
919 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.ialpha);
922 if (surface->compositor->method == CompositeMethod::AlphaMask) {
923 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
924 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
925 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
929 if (opacity == 255) return _rasterScaledRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
930 else return _rasterScaledTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale);
936 /************************************************************************/
937 /* RLE Direct RGBA Image */
938 /************************************************************************/
940 static bool _rasterDirectMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
942 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
944 auto span = image->rle->spans;
945 auto cbuffer = surface->compositor->image.data;
947 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
948 auto dst = &surface->buffer[span->y * surface->stride + span->x];
949 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
950 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
951 auto alpha = _multiplyAlpha(span->coverage, opacity);
953 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
954 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
955 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
958 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
959 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp)));
960 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
968 static bool _rasterDirectMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t (*blendMethod)(uint32_t))
970 TVGLOG("SW_ENGINE", "Direct Masked Rle Image");
972 auto span = image->rle->spans;
973 auto cbuffer = surface->compositor->image.data;
975 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
976 auto dst = &surface->buffer[span->y * surface->stride + span->x];
977 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
978 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
979 if (span->coverage == 255) {
980 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
981 auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp));
982 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
985 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) {
986 auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(span->coverage, blendMethod(*cmp)));
987 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
995 static bool _rasterDirectTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
997 auto span = image->rle->spans;
999 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
1000 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1001 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
1002 auto alpha = _multiplyAlpha(span->coverage, opacity);
1003 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1004 auto src = ALPHA_BLEND(*img, alpha);
1005 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1012 static bool _rasterDirectRleRGBAImage(SwSurface* surface, const SwImage* image)
1014 auto span = image->rle->spans;
1016 for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
1017 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1018 auto img = image->data + (span->y + image->oy) * image->stride + (span->x + image->ox);
1019 if (span->coverage == 255) {
1020 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1021 *dst = *img + ALPHA_BLEND(*dst, surface->blender.ialpha(*img));
1024 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) {
1025 auto src = ALPHA_BLEND(*img, span->coverage);
1026 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1034 static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32_t opacity)
1036 if (_compositing(surface)) {
1037 if (opacity == 255) {
1038 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1039 return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.alpha);
1040 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1041 return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.ialpha);
1044 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1045 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.alpha);
1046 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1047 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.ialpha);
1051 if (opacity == 255) return _rasterDirectRleRGBAImage(surface, image);
1052 else return _rasterDirectTranslucentRleRGBAImage(surface, image, opacity);
1058 /************************************************************************/
1059 /* Transformed RGBA Image */
1060 /************************************************************************/
1062 static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1064 if (_compositing(surface)) {
1065 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1066 return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.alpha);
1067 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1068 return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.ialpha);
1071 return _rasterTexmapPolygon(surface, image, transform, region, opacity, nullptr);
1077 /************************************************************************/
1078 /*Scaled RGBA Image */
1079 /************************************************************************/
1082 static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
1084 TVGLOG("SW_ENGINE", "Scaled Masked Image");
1086 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1087 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
1090 if (image->scale < DOWN_SCALE_TOLERANCE) {
1091 for (auto y = region.min.y; y < region.max.y; ++y) {
1094 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1095 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
1096 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
1097 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1098 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha);
1099 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1101 dbuffer += surface->stride;
1102 cbuffer += surface->compositor->image.stride;
1106 for (auto y = region.min.y; y < region.max.y; ++y) {
1109 auto sy = fabsf(y * itransform->e22 + itransform->e23);
1110 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
1111 auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp));
1112 auto sx = fabsf(x * itransform->e11 + itransform->e13);
1113 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha);
1114 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1116 dbuffer += surface->stride;
1117 cbuffer += surface->compositor->image.stride;
1124 static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t))
1126 TVGLOG("SW_ENGINE", "Scaled Masked Image");
1128 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1129 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x);
1132 if (image->scale < DOWN_SCALE_TOLERANCE) {
1133 for (auto y = region.min.y; y < region.max.y; ++y) {
1136 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1137 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
1138 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1139 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp));
1140 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1142 dbuffer += surface->stride;
1143 cbuffer += surface->compositor->image.stride;
1147 for (auto y = region.min.y; y < region.max.y; ++y) {
1150 auto sy = fabsf(y * itransform->e22 + itransform->e23);
1151 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
1152 auto sx = fabsf(x * itransform->e11 + itransform->e13);
1153 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp));
1154 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1156 dbuffer += surface->stride;
1157 cbuffer += surface->compositor->image.stride;
1164 static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale)
1166 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1169 if (image->scale < DOWN_SCALE_TOLERANCE) {
1170 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1171 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1173 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1174 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1175 auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity);
1176 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1181 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1182 auto sy = fabsf(y * itransform->e22 + itransform->e23);
1184 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1185 auto sx = fabsf(x * itransform->e11 + itransform->e13);
1186 auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity);
1187 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1195 static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale)
1197 auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x);
1200 if (image->scale < DOWN_SCALE_TOLERANCE) {
1201 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1202 auto sy = static_cast<uint32_t>(y * itransform->e22 + itransform->e23);
1204 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1205 auto sx = static_cast<uint32_t>(x * itransform->e11 + itransform->e13);
1206 auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale);
1207 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1212 for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
1213 auto sy = fabsf(y * itransform->e22 + itransform->e23);
1215 for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
1216 auto sx = fabsf(x * itransform->e11 + itransform->e13);
1217 auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy);
1218 *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src));
1226 static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1229 if (transform && !mathInverse(transform, &itransform)) return false;
1231 auto halfScale = _halfScale(image->scale);
1233 if (_compositing(surface)) {
1234 if (opacity == 255) {
1235 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1236 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.alpha);
1237 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1238 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.ialpha);
1241 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1242 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha);
1243 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1244 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha);
1248 if (opacity == 255) return _rasterScaledRGBAImage(surface, image, &itransform, region, halfScale);
1249 else return _rasterScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale);
1255 /************************************************************************/
1256 /* Direct RGBA Image */
1257 /************************************************************************/
1259 static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t (*blendMethod)(uint32_t))
1261 TVGLOG("SW_ENGINE", "Direct Masked Image");
1263 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1264 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
1265 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
1267 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1268 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
1270 for (uint32_t y = 0; y < h2; ++y) {
1274 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
1275 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1276 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1278 buffer += surface->stride;
1279 cbuffer += surface->compositor->image.stride;
1280 sbuffer += image->stride;
1286 static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t))
1288 TVGLOG("SW_ENGINE", "Direct Masked Translucent Image");
1290 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1291 auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
1292 auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
1294 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1295 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
1297 for (uint32_t y = 0; y < h2; ++y) {
1301 for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
1302 auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp)));
1303 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1305 buffer += surface->stride;
1306 cbuffer += surface->compositor->image.stride;
1307 sbuffer += image->stride;
1313 static bool _rasterDirectTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1315 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1316 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1318 for (auto y = region.min.y; y < region.max.y; ++y) {
1321 for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
1322 auto tmp = ALPHA_BLEND(*src, opacity);
1323 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1325 dbuffer += surface->stride;
1326 sbuffer += image->stride;
1332 static bool _rasterDirectRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
1334 auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x];
1335 auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
1337 for (auto y = region.min.y; y < region.max.y; ++y) {
1340 for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
1341 *dst = *src + ALPHA_BLEND(*dst, surface->blender.ialpha(*src));
1343 dbuffer += surface->stride;
1344 sbuffer += image->stride;
1350 //Blenders for the following scenarios: [Composition / Non-Composition] * [Opaque / Translucent]
1351 static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity)
1353 if (_compositing(surface)) {
1354 if (opacity == 255) {
1355 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1356 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.alpha);
1357 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1358 return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.ialpha);
1361 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1362 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.alpha);
1363 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1364 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.ialpha);
1368 if (opacity == 255) return _rasterDirectRGBAImage(surface, image, region);
1369 else return _rasterDirectTranslucentRGBAImage(surface, image, region, opacity);
1375 //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed]
1376 static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity)
1380 if (image->direct) return _directRleRGBAImage(surface, image, opacity);
1381 else if (image->scaled) return _scaledRleRGBAImage(surface, image, transform, region, opacity);
1382 //OPTIMIZE_ME: Replace with the TexMap Rasterizer
1383 else return _transformedRleRGBAImage(surface, image, transform, opacity);
1386 if (image->direct) return _directRGBAImage(surface, image, region, opacity);
1387 else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity);
1388 else return _transformedRGBAImage(surface, image, transform, region, opacity);
1393 /************************************************************************/
1394 /* Rect Linear Gradient */
1395 /************************************************************************/
1397 static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1399 if (fill->linear.len < FLT_EPSILON) return false;
1401 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1402 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1403 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1404 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1406 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1407 if (!sbuffer) return false;
1409 for (uint32_t y = 0; y < h; ++y) {
1410 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1414 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1415 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1416 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1418 buffer += surface->stride;
1419 cbuffer += surface->stride;
1425 static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1427 if (fill->linear.len < FLT_EPSILON) return false;
1429 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1430 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1431 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1433 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1434 if (!sbuffer) return false;
1436 for (uint32_t y = 0; y < h; ++y) {
1438 fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
1439 for (uint32_t x = 0; x < w; ++x, ++dst) {
1440 *dst = sbuffer[x] + ALPHA_BLEND(*dst, surface->blender.ialpha(sbuffer[x]));
1442 buffer += surface->stride;
1448 static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1450 if (fill->linear.len < FLT_EPSILON) return false;
1452 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1453 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1454 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1456 for (uint32_t y = 0; y < h; ++y) {
1457 fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
1463 static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1465 if (_compositing(surface)) {
1466 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1467 return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1468 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1469 return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1472 if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
1473 else _rasterSolidLinearGradientRect(surface, region, fill);
1479 /************************************************************************/
1480 /* Rle Linear Gradient */
1481 /************************************************************************/
1483 static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1485 if (fill->linear.len < FLT_EPSILON) return false;
1487 auto span = rle->spans;
1488 auto cbuffer = surface->compositor->image.data;
1489 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1490 if (!buffer) return false;
1492 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1493 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1494 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1495 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1497 if (span->coverage == 255) {
1498 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1499 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1500 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1503 auto ialpha = 255 - span->coverage;
1504 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1505 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1506 tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
1507 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1515 static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1517 if (fill->linear.len < FLT_EPSILON) return false;
1519 auto span = rle->spans;
1520 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1521 if (!buffer) return false;
1523 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1524 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1525 fillFetchLinear(fill, buffer, span->y, span->x, span->len);
1526 if (span->coverage == 255) {
1527 for (uint32_t i = 0; i < span->len; ++i, ++dst) {
1528 *dst = buffer[i] + ALPHA_BLEND(*dst, surface->blender.ialpha(buffer[i]));
1531 for (uint32_t i = 0; i < span->len; ++i, ++dst) {
1532 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1533 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1541 static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1543 if (fill->linear.len < FLT_EPSILON) return false;
1545 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1546 if (!buf) return false;
1548 auto span = rle->spans;
1550 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1551 if (span->coverage == 255) {
1552 fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
1554 fillFetchLinear(fill, buf, span->y, span->x, span->len);
1555 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1556 for (uint32_t i = 0; i < span->len; ++i) {
1557 dst[i] = INTERPOLATE(span->coverage, buf[i], dst[i]);
1565 static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1567 if (!rle) return false;
1569 if (_compositing(surface)) {
1570 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1571 return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1572 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1573 return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1576 if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
1577 else return _rasterSolidLinearGradientRle(surface, rle, fill);
1583 /************************************************************************/
1584 /* Rect Radial Gradient */
1585 /************************************************************************/
1587 static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1589 if (fill->radial.a < FLT_EPSILON) return false;
1591 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1592 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1593 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1594 auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;
1596 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1597 if (!sbuffer) return false;
1599 for (uint32_t y = 0; y < h; ++y) {
1600 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1604 for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
1605 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1606 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1608 buffer += surface->stride;
1609 cbuffer += surface->stride;
1615 static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1617 if (fill->radial.a < FLT_EPSILON) return false;
1619 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1620 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1621 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1623 auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
1624 if (!sbuffer) return false;
1626 for (uint32_t y = 0; y < h; ++y) {
1628 fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
1629 for (uint32_t x = 0; x < w; ++x, ++dst) {
1630 *dst = sbuffer[x] + ALPHA_BLEND(*dst, surface->blender.ialpha(sbuffer[x]));
1632 buffer += surface->stride;
1638 static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1640 if (fill->radial.a < FLT_EPSILON) return false;
1642 auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
1643 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
1644 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
1646 for (uint32_t y = 0; y < h; ++y) {
1647 auto dst = &buffer[y * surface->stride];
1648 fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
1654 static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
1656 if (_compositing(surface)) {
1657 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1658 return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha);
1659 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1660 return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha);
1663 if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
1664 else return _rasterSolidRadialGradientRect(surface, region, fill);
1670 /************************************************************************/
1671 /* RLE Radial Gradient */
1672 /************************************************************************/
1674 static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t))
1676 if (fill->radial.a < FLT_EPSILON) return false;
1678 auto span = rle->spans;
1679 auto cbuffer = surface->compositor->image.data;
1680 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1681 if (!buffer) return false;
1683 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1684 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1685 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1686 auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x];
1688 if (span->coverage == 255) {
1689 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1690 auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
1691 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1694 for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
1695 auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blendMethod(*cmp)), *dst);
1696 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1704 static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1706 if (fill->radial.a < FLT_EPSILON) return false;
1708 auto span = rle->spans;
1709 auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1710 if (!buffer) return false;
1712 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1713 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1714 fillFetchRadial(fill, buffer, span->y, span->x, span->len);
1715 if (span->coverage == 255) {
1716 for (uint32_t i = 0; i < span->len; ++i, ++dst) {
1717 *dst = buffer[i] + ALPHA_BLEND(*dst, surface->blender.ialpha(buffer[i]));
1720 for (uint32_t i = 0; i < span->len; ++i, ++dst) {
1721 auto tmp = ALPHA_BLEND(buffer[i], span->coverage);
1722 *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp));
1730 static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1732 if (fill->radial.a < FLT_EPSILON) return false;
1734 auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
1735 if (!buf) return false;
1737 auto span = rle->spans;
1739 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
1740 auto dst = &surface->buffer[span->y * surface->stride + span->x];
1741 if (span->coverage == 255) {
1742 fillFetchRadial(fill, dst, span->y, span->x, span->len);
1744 fillFetchRadial(fill, buf, span->y, span->x, span->len);
1745 auto ialpha = 255 - span->coverage;
1746 for (uint32_t i = 0; i < span->len; ++i, ++dst) {
1747 *dst = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(*dst, ialpha);
1755 static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
1757 if (!rle) return false;
1759 if (_compositing(surface)) {
1760 if (surface->compositor->method == CompositeMethod::AlphaMask) {
1761 return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha);
1762 } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
1763 return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha);
1766 if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
1767 else return _rasterSolidRadialGradientRle(surface, rle, fill);
1773 /************************************************************************/
1774 /* External Class Implementation */
1775 /************************************************************************/
1777 void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
1779 #if defined(THORVG_AVX_VECTOR_SUPPORT)
1780 avxRasterRGBA32(dst, val, offset, len);
1781 #elif defined(THORVG_NEON_VECTOR_SUPPORT)
1782 neonRasterRGBA32(dst, val, offset, len);
1784 cRasterRGBA32(dst, val, offset, len);
1789 bool rasterCompositor(SwSurface* surface)
1791 if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
1792 surface->blender.join = _abgrJoin;
1793 } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
1794 surface->blender.join = _argbJoin;
1796 //What Color Space ???
1799 surface->blender.alpha = _colorAlpha;
1800 surface->blender.ialpha = _colorInvAlpha;
1806 bool rasterClear(SwSurface* surface)
1808 if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false;
1810 if (surface->w == surface->stride) {
1811 rasterRGBA32(surface->buffer, 0x00000000, 0, surface->w * surface->h);
1813 for (uint32_t i = 0; i < surface->h; i++) {
1814 rasterRGBA32(surface->buffer + surface->stride * i, 0x00000000, 0, surface->w);
1821 void rasterUnpremultiply(SwSurface* surface)
1823 //TODO: Create simd avx and neon version
1824 for (uint32_t y = 0; y < surface->h; y++) {
1825 auto buffer = surface->buffer + surface->stride * y;
1826 for (uint32_t x = 0; x < surface->w; ++x) {
1827 uint8_t a = buffer[x] >> 24;
1830 } else if (a == 0) {
1831 buffer[x] = 0x00ffffff;
1833 uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
1834 uint16_t g = ((buffer[x]) & 0xff00) / a;
1835 uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
1836 if (r > 0xff) r = 0xff;
1837 if (g > 0xff) g = 0xff;
1838 if (b > 0xff) b = 0xff;
1839 buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
1846 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
1848 if (!shape->fill) return false;
1850 if (shape->fastTrack) {
1851 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
1852 else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
1854 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
1855 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
1861 bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
1863 if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
1865 if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1866 else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
1872 bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1875 r = _multiplyAlpha(r, a);
1876 g = _multiplyAlpha(g, a);
1877 b = _multiplyAlpha(b, a);
1880 auto color = surface->blender.join(r, g, b, a);
1882 if (shape->fastTrack) return _rasterRect(surface, shape->bbox, color, a);
1883 else return _rasterRle(surface, shape->rle, color, a);
1887 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
1890 r = _multiplyAlpha(r, a);
1891 g = _multiplyAlpha(g, a);
1892 b = _multiplyAlpha(b, a);
1895 auto color = surface->blender.join(r, g, b, a);
1897 return _rasterRle(surface, shape->strokeRle, color, a);
1901 bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity)
1904 if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= surface->w || bbox.min.y >= surface->h) return false;
1906 //TOOD: switch (image->format)
1907 //TODO: case: _rasterRGBImage()
1908 //TODO: case: _rasterGrayscaleImage()
1909 //TODO: case: _rasterAlphaImage()
1911 return _rasterRGBAImage(surface, image, transform, bbox, opacity);