1/*
2 * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
3
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23struct AALine
24{
25 int32_t x[2];
26 int32_t coverage[2];
27 int32_t length[2];
28};
29
30struct AASpans
31{
32 AALine *lines;
33 int32_t yStart;
34 int32_t yEnd;
35};
36
37static inline void _swap(float& a, float& b, float& tmp)
38{
39 tmp = a;
40 a = b;
41 b = tmp;
42}
43
44
45//Careful! Shared resource, No support threading
46static float dudx, dvdx;
47static float dxdya, dxdyb, dudya, dvdya;
48static float xa, xb, ua, va;
49
50
51//Y Range exception handling
52static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, int& yEnd)
53{
54 int32_t regionTop, regionBottom;
55
56 if (region) {
57 regionTop = region->min.y;
58 regionBottom = region->max.y;
59 } else {
60 regionTop = image->rle->spans->y;
61 regionBottom = image->rle->spans[image->rle->size - 1].y;
62 }
63
64 if (yStart >= regionBottom) return false;
65
66 if (yStart < regionTop) yStart = regionTop;
67 if (yEnd > regionBottom) yEnd = regionBottom;
68
69 return true;
70}
71
72
73static void _rasterMaskedPolygonImageSegmentInt(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag)
74{
75 float _dudx = dudx, _dvdx = dvdx;
76 float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
77 float _xa = xa, _xb = xb, _ua = ua, _va = va;
78 auto sbuf = image->buf32;
79 int32_t sw = static_cast<int32_t>(image->stride);
80 int32_t sh = image->h;
81 int32_t x1, x2, ar, ab, iru, irv, px, ay;
82 int32_t vv = 0, uu = 0;
83 int32_t minx = INT32_MAX, maxx = INT32_MIN;
84 float dx, u, v, iptr;
85 auto cbuffer = surface->compositor->image.buf32;
86 SwSpan* span = nullptr; //used only when rle based.
87
88 if (!_arrange(image, region, yStart, yEnd)) return;
89
90 //Clear out of the Polygon vertical ranges
91 auto size = surface->compositor->bbox.max.x - surface->compositor->bbox.min.x;
92 if (dirFlag == 1) { //left top case.
93 for(int y = surface->compositor->bbox.min.y; y < yStart; ++y) {
94 rasterPixel32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
95 }
96 }
97 if (dirFlag == 4) { //right bottom case.
98 for(int y = yEnd; y < surface->compositor->bbox.max.y; ++y) {
99 rasterPixel32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size);
100 }
101 }
102
103 //Loop through all lines in the segment
104 uint32_t spanIdx = 0;
105
106 if (region) {
107 minx = region->min.x;
108 maxx = region->max.x;
109 } else {
110 span = image->rle->spans;
111 while (span->y < yStart) {
112 ++span;
113 ++spanIdx;
114 }
115 }
116
117 for (int32_t y = yStart; y < yEnd; ++y) {
118 auto cmp = &cbuffer[y * surface->compositor->image.stride];
119 x1 = (int32_t)_xa;
120 x2 = (int32_t)_xb;
121
122 if (!region) {
123 minx = INT32_MAX;
124 maxx = INT32_MIN;
125 //one single row, could be consisted of multiple spans.
126 while (span->y == y && spanIdx < image->rle->size) {
127 if (minx > span->x) minx = span->x;
128 if (maxx < span->x + span->len) maxx = span->x + span->len;
129 ++span;
130 ++spanIdx;
131 }
132 }
133
134 if (x1 < minx) x1 = minx;
135 if (x2 > maxx) x2 = maxx;
136
137 //Anti-Aliasing frames
138 //FIXME: this aa must be applied before masking op
139 ay = y - aaSpans->yStart;
140 if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
141 if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
142
143 //Range allowed
144 if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
145 for (int32_t x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) {
146 //Range allowed
147 if (x >= x1 && x < x2) {
148 //Perform subtexel pre-stepping on UV
149 dx = 1 - (_xa - x1);
150 u = _ua + dx * _dudx;
151 v = _va + dx * _dvdx;
152 if ((uint32_t)v >= image->h) {
153 cmp[x] = 0;
154 } else {
155 if (opacity == 255) {
156 uu = (int) u;
157 if (uu >= sw) continue;
158 vv = (int) v;
159 if (vv >= sh) continue;
160
161 ar = (int)(255 * (1 - modff(u, &iptr)));
162 ab = (int)(255 * (1 - modff(v, &iptr)));
163 iru = uu + 1;
164 irv = vv + 1;
165
166 px = *(sbuf + (vv * sw) + uu);
167
168 /* horizontal interpolate */
169 if (iru < sw) {
170 /* right pixel */
171 int px2 = *(sbuf + (vv * sw) + iru);
172 px = INTERPOLATE(px, px2, ar);
173 }
174 /* vertical interpolate */
175 if (irv < sh) {
176 /* bottom pixel */
177 int px2 = *(sbuf + (irv * sw) + uu);
178
179 /* horizontal interpolate */
180 if (iru < sw) {
181 /* bottom right pixel */
182 int px3 = *(sbuf + (irv * sw) + iru);
183 px2 = INTERPOLATE(px2, px3, ar);
184 }
185 px = INTERPOLATE(px, px2, ab);
186 }
187 cmp[x] = ALPHA_BLEND(cmp[x], A(px));
188
189 //Step UV horizontally
190 u += _dudx;
191 v += _dvdx;
192 } else {
193 uu = (int) u;
194 if (uu >= sw) continue;
195 vv = (int) v;
196 if (vv >= sh) continue;
197
198 ar = (int)(255 * (1 - modff(u, &iptr)));
199 ab = (int)(255 * (1 - modff(v, &iptr)));
200 iru = uu + 1;
201 irv = vv + 1;
202
203 px = *(sbuf + (vv * sw) + uu);
204
205 /* horizontal interpolate */
206 if (iru < sw) {
207 /* right pixel */
208 int px2 = *(sbuf + (vv * sw) + iru);
209 px = INTERPOLATE(px, px2, ar);
210 }
211 /* vertical interpolate */
212 if (irv < sh) {
213 /* bottom pixel */
214 int px2 = *(sbuf + (irv * sw) + uu);
215
216 /* horizontal interpolate */
217 if (iru < sw) {
218 /* bottom right pixel */
219 int px3 = *(sbuf + (irv * sw) + iru);
220 px2 = INTERPOLATE(px2, px3, ar);
221 }
222 px = INTERPOLATE(px, px2, ab);
223 }
224 cmp[x] = ALPHA_BLEND(cmp[x], MULTIPLY(A(px), opacity));
225
226 //Step UV horizontally
227 u += _dudx;
228 v += _dvdx;
229 }
230 }
231 } else {
232 //Clear out of polygon horizontal range
233 if (x < x1 && (dirFlag == 1 || dirFlag == 2)) cmp[x] = 0;
234 else if (x >= x2 && (dirFlag == 3 || dirFlag == 4)) cmp[x] = 0;
235 }
236 }
237 }
238 //Step along both edges
239 _xa += _dxdya;
240 _xb += _dxdyb;
241 _ua += _dudya;
242 _va += _dvdya;
243 }
244 xa = _xa;
245 xb = _xb;
246 ua = _ua;
247 va = _va;
248}
249
250
251static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImage* image, const SwBBox* region, SwBlender maskOp, SwBlender amaskOp, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity)
252{
253 float _dudx = dudx, _dvdx = dvdx;
254 float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
255 float _xa = xa, _xb = xb, _ua = ua, _va = va;
256 auto sbuf = image->buf32;
257 int32_t sw = static_cast<int32_t>(image->stride);
258 int32_t sh = image->h;
259 int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
260 int32_t vv = 0, uu = 0;
261 int32_t minx = INT32_MAX, maxx = INT32_MIN;
262 float dx, u, v, iptr;
263 SwSpan* span = nullptr; //used only when rle based.
264
265 if (!_arrange(image, region, yStart, yEnd)) return;
266
267 //Loop through all lines in the segment
268 uint32_t spanIdx = 0;
269
270 if (region) {
271 minx = region->min.x;
272 maxx = region->max.x;
273 } else {
274 span = image->rle->spans;
275 while (span->y < yStart) {
276 ++span;
277 ++spanIdx;
278 }
279 }
280
281 y = yStart;
282
283 while (y < yEnd) {
284 x1 = (int32_t)_xa;
285 x2 = (int32_t)_xb;
286
287 if (!region) {
288 minx = INT32_MAX;
289 maxx = INT32_MIN;
290 //one single row, could be consisted of multiple spans.
291 while (span->y == y && spanIdx < image->rle->size) {
292 if (minx > span->x) minx = span->x;
293 if (maxx < span->x + span->len) maxx = span->x + span->len;
294 ++span;
295 ++spanIdx;
296 }
297 }
298 if (x1 < minx) x1 = minx;
299 if (x2 > maxx) x2 = maxx;
300
301 //Anti-Aliasing frames
302 ay = y - aaSpans->yStart;
303 if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
304 if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
305
306 //Range allowed
307 if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
308
309 //Perform subtexel pre-stepping on UV
310 dx = 1 - (_xa - x1);
311 u = _ua + dx * _dudx;
312 v = _va + dx * _dvdx;
313
314 x = x1;
315
316 auto cmp = &surface->compositor->image.buf32[y * surface->compositor->image.stride + x1];
317
318 if (opacity == 255) {
319 //Draw horizontal line
320 while (x++ < x2) {
321 uu = (int) u;
322 if (uu >= sw) continue;
323 vv = (int) v;
324 if (vv >= sh) continue;
325
326 ar = (int)(255 * (1 - modff(u, &iptr)));
327 ab = (int)(255 * (1 - modff(v, &iptr)));
328 iru = uu + 1;
329 irv = vv + 1;
330
331 px = *(sbuf + (vv * sw) + uu);
332
333 /* horizontal interpolate */
334 if (iru < sw) {
335 /* right pixel */
336 int px2 = *(sbuf + (vv * sw) + iru);
337 px = INTERPOLATE(px, px2, ar);
338 }
339 /* vertical interpolate */
340 if (irv < sh) {
341 /* bottom pixel */
342 int px2 = *(sbuf + (irv * sw) + uu);
343
344 /* horizontal interpolate */
345 if (iru < sw) {
346 /* bottom right pixel */
347 int px3 = *(sbuf + (irv * sw) + iru);
348 px2 = INTERPOLATE(px2, px3, ar);
349 }
350 px = INTERPOLATE(px, px2, ab);
351 }
352 *cmp = maskOp(px, *cmp, IA(px));
353 ++cmp;
354
355 //Step UV horizontally
356 u += _dudx;
357 v += _dvdx;
358 //range over?
359 if ((uint32_t)v >= image->h) break;
360 }
361 } else {
362 //Draw horizontal line
363 while (x++ < x2) {
364 uu = (int) u;
365 if (uu >= sw) continue;
366 vv = (int) v;
367 if (vv >= sh) continue;
368
369 ar = (int)(255 * (1 - modff(u, &iptr)));
370 ab = (int)(255 * (1 - modff(v, &iptr)));
371 iru = uu + 1;
372 irv = vv + 1;
373
374 px = *(sbuf + (vv * sw) + uu);
375
376 /* horizontal interpolate */
377 if (iru < sw) {
378 /* right pixel */
379 int px2 = *(sbuf + (vv * sw) + iru);
380 px = INTERPOLATE(px, px2, ar);
381 }
382 /* vertical interpolate */
383 if (irv < sh) {
384 /* bottom pixel */
385 int px2 = *(sbuf + (irv * sw) + uu);
386
387 /* horizontal interpolate */
388 if (iru < sw) {
389 /* bottom right pixel */
390 int px3 = *(sbuf + (irv * sw) + iru);
391 px2 = INTERPOLATE(px2, px3, ar);
392 }
393 px = INTERPOLATE(px, px2, ab);
394 }
395 *cmp = amaskOp(px, *cmp, opacity);
396 ++cmp;
397
398 //Step UV horizontally
399 u += _dudx;
400 v += _dvdx;
401 //range over?
402 if ((uint32_t)v >= image->h) break;
403 }
404 }
405 }
406
407 //Step along both edges
408 _xa += _dxdya;
409 _xb += _dxdyb;
410 _ua += _dudya;
411 _va += _dvdya;
412
413 if (!region && spanIdx >= image->rle->size) break;
414
415 ++y;
416 }
417 xa = _xa;
418 xb = _xb;
419 ua = _ua;
420 va = _va;
421}
422
423
424static void _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0)
425{
426 if (surface->compositor->method == CompositeMethod::IntersectMask) {
427 _rasterMaskedPolygonImageSegmentInt(surface, image, region, yStart, yEnd, aaSpans, opacity, dirFlag);
428 } else if (auto opMask = _getMaskOp(surface->compositor->method)) {
429 //Other Masking operations: Add, Subtract, Difference ...
430 _rasterMaskedPolygonImageSegmentDup(surface, image, region, opMask, _getAMaskOp(surface->compositor->method), yStart, yEnd, aaSpans, opacity);
431 }
432}
433
434
435static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity)
436{
437 float _dudx = dudx, _dvdx = dvdx;
438 float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
439 float _xa = xa, _xb = xb, _ua = ua, _va = va;
440 auto sbuf = image->buf32;
441 auto dbuf = surface->buf32;
442 int32_t sw = static_cast<int32_t>(image->stride);
443 int32_t sh = image->h;
444 int32_t dw = surface->stride;
445 int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
446 int32_t vv = 0, uu = 0;
447 int32_t minx = INT32_MAX, maxx = INT32_MIN;
448 float dx, u, v, iptr;
449 uint32_t* buf;
450 SwSpan* span = nullptr; //used only when rle based.
451
452 if (!_arrange(image, region, yStart, yEnd)) return;
453
454 //Loop through all lines in the segment
455 uint32_t spanIdx = 0;
456
457 if (region) {
458 minx = region->min.x;
459 maxx = region->max.x;
460 } else {
461 span = image->rle->spans;
462 while (span->y < yStart) {
463 ++span;
464 ++spanIdx;
465 }
466 }
467
468 y = yStart;
469
470 while (y < yEnd) {
471 x1 = (int32_t)_xa;
472 x2 = (int32_t)_xb;
473
474 if (!region) {
475 minx = INT32_MAX;
476 maxx = INT32_MIN;
477 //one single row, could be consisted of multiple spans.
478 while (span->y == y && spanIdx < image->rle->size) {
479 if (minx > span->x) minx = span->x;
480 if (maxx < span->x + span->len) maxx = span->x + span->len;
481 ++span;
482 ++spanIdx;
483 }
484 }
485 if (x1 < minx) x1 = minx;
486 if (x2 > maxx) x2 = maxx;
487
488 //Anti-Aliasing frames
489 ay = y - aaSpans->yStart;
490 if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
491 if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
492
493 //Range allowed
494 if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
495
496 //Perform subtexel pre-stepping on UV
497 dx = 1 - (_xa - x1);
498 u = _ua + dx * _dudx;
499 v = _va + dx * _dvdx;
500
501 buf = dbuf + ((y * dw) + x1);
502
503 x = x1;
504
505 if (opacity == 255) {
506 //Draw horizontal line
507 while (x++ < x2) {
508 uu = (int) u;
509 if (uu >= sw) continue;
510 vv = (int) v;
511 if (vv >= sh) continue;
512
513 ar = (int)(255 * (1 - modff(u, &iptr)));
514 ab = (int)(255 * (1 - modff(v, &iptr)));
515 iru = uu + 1;
516 irv = vv + 1;
517
518 px = *(sbuf + (vv * sw) + uu);
519
520 /* horizontal interpolate */
521 if (iru < sw) {
522 /* right pixel */
523 int px2 = *(sbuf + (vv * sw) + iru);
524 px = INTERPOLATE(px, px2, ar);
525 }
526 /* vertical interpolate */
527 if (irv < sh) {
528 /* bottom pixel */
529 int px2 = *(sbuf + (irv * sw) + uu);
530
531 /* horizontal interpolate */
532 if (iru < sw) {
533 /* bottom right pixel */
534 int px3 = *(sbuf + (irv * sw) + iru);
535 px2 = INTERPOLATE(px2, px3, ar);
536 }
537 px = INTERPOLATE(px, px2, ab);
538 }
539 *buf = surface->blender(px, *buf, IA(px));
540 ++buf;
541
542 //Step UV horizontally
543 u += _dudx;
544 v += _dvdx;
545 //range over?
546 if ((uint32_t)v >= image->h) break;
547 }
548 } else {
549 //Draw horizontal line
550 while (x++ < x2) {
551 uu = (int) u;
552 if (uu >= sw) continue;
553 vv = (int) v;
554 if (vv >= sh) continue;
555
556 ar = (int)(255 * (1 - modff(u, &iptr)));
557 ab = (int)(255 * (1 - modff(v, &iptr)));
558 iru = uu + 1;
559 irv = vv + 1;
560
561 px = *(sbuf + (vv * sw) + uu);
562
563 /* horizontal interpolate */
564 if (iru < sw) {
565 /* right pixel */
566 int px2 = *(sbuf + (vv * sw) + iru);
567 px = INTERPOLATE(px, px2, ar);
568 }
569 /* vertical interpolate */
570 if (irv < sh) {
571 /* bottom pixel */
572 int px2 = *(sbuf + (irv * sw) + uu);
573
574 /* horizontal interpolate */
575 if (iru < sw) {
576 /* bottom right pixel */
577 int px3 = *(sbuf + (irv * sw) + iru);
578 px2 = INTERPOLATE(px2, px3, ar);
579 }
580 px = INTERPOLATE(px, px2, ab);
581 }
582 auto src = ALPHA_BLEND(px, opacity);
583 *buf = surface->blender(src, *buf, IA(src));
584 ++buf;
585
586 //Step UV horizontally
587 u += _dudx;
588 v += _dvdx;
589 //range over?
590 if ((uint32_t)v >= image->h) break;
591 }
592 }
593 }
594
595 //Step along both edges
596 _xa += _dxdya;
597 _xb += _dxdyb;
598 _ua += _dudya;
599 _va += _dvdya;
600
601 if (!region && spanIdx >= image->rle->size) break;
602
603 ++y;
604 }
605 xa = _xa;
606 xb = _xb;
607 ua = _ua;
608 va = _va;
609}
610
611
612static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, bool matting)
613{
614 float _dudx = dudx, _dvdx = dvdx;
615 float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
616 float _xa = xa, _xb = xb, _ua = ua, _va = va;
617 auto sbuf = image->buf32;
618 auto dbuf = surface->buf32;
619 int32_t sw = static_cast<int32_t>(image->stride);
620 int32_t sh = image->h;
621 int32_t dw = surface->stride;
622 int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
623 int32_t vv = 0, uu = 0;
624 int32_t minx = INT32_MAX, maxx = INT32_MIN;
625 float dx, u, v, iptr;
626 uint32_t* buf;
627 SwSpan* span = nullptr; //used only when rle based.
628
629 //for matting(composition)
630 auto csize = matting ? surface->compositor->image.channelSize: 0;
631 auto alpha = matting ? surface->alpha(surface->compositor->method) : nullptr;
632 uint8_t* cmp = nullptr;
633
634 if (!_arrange(image, region, yStart, yEnd)) return;
635
636 //Loop through all lines in the segment
637 uint32_t spanIdx = 0;
638
639 if (region) {
640 minx = region->min.x;
641 maxx = region->max.x;
642 } else {
643 span = image->rle->spans;
644 while (span->y < yStart) {
645 ++span;
646 ++spanIdx;
647 }
648 }
649
650 y = yStart;
651
652 while (y < yEnd) {
653 x1 = (int32_t)_xa;
654 x2 = (int32_t)_xb;
655
656 if (!region) {
657 minx = INT32_MAX;
658 maxx = INT32_MIN;
659 //one single row, could be consisted of multiple spans.
660 while (span->y == y && spanIdx < image->rle->size) {
661 if (minx > span->x) minx = span->x;
662 if (maxx < span->x + span->len) maxx = span->x + span->len;
663 ++span;
664 ++spanIdx;
665 }
666 }
667 if (x1 < minx) x1 = minx;
668 if (x2 > maxx) x2 = maxx;
669
670 //Anti-Aliasing frames
671 ay = y - aaSpans->yStart;
672 if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
673 if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
674
675 //Range allowed
676 if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
677
678 //Perform subtexel pre-stepping on UV
679 dx = 1 - (_xa - x1);
680 u = _ua + dx * _dudx;
681 v = _va + dx * _dvdx;
682
683 buf = dbuf + ((y * dw) + x1);
684
685 x = x1;
686
687 if (matting) cmp = &surface->compositor->image.buf8[(y * surface->compositor->image.stride + x1) * csize];
688
689 if (opacity == 255) {
690 //Draw horizontal line
691 while (x++ < x2) {
692 uu = (int) u;
693 if (uu >= sw) continue;
694 vv = (int) v;
695 if (vv >= sh) continue;
696
697 ar = (int)(255 * (1 - modff(u, &iptr)));
698 ab = (int)(255 * (1 - modff(v, &iptr)));
699 iru = uu + 1;
700 irv = vv + 1;
701
702 px = *(sbuf + (vv * sw) + uu);
703
704 /* horizontal interpolate */
705 if (iru < sw) {
706 /* right pixel */
707 int px2 = *(sbuf + (vv * sw) + iru);
708 px = INTERPOLATE(px, px2, ar);
709 }
710 /* vertical interpolate */
711 if (irv < sh) {
712 /* bottom pixel */
713 int px2 = *(sbuf + (irv * sw) + uu);
714
715 /* horizontal interpolate */
716 if (iru < sw) {
717 /* bottom right pixel */
718 int px3 = *(sbuf + (irv * sw) + iru);
719 px2 = INTERPOLATE(px2, px3, ar);
720 }
721 px = INTERPOLATE(px, px2, ab);
722 }
723 uint32_t src;
724 if (matting) {
725 src = ALPHA_BLEND(px, alpha(cmp));
726 cmp += csize;
727 } else {
728 src = px;
729 }
730 *buf = src + ALPHA_BLEND(*buf, IA(src));
731 ++buf;
732
733 //Step UV horizontally
734 u += _dudx;
735 v += _dvdx;
736 //range over?
737 if ((uint32_t)v >= image->h) break;
738 }
739 } else {
740 //Draw horizontal line
741 while (x++ < x2) {
742 uu = (int) u;
743 vv = (int) v;
744
745 ar = (int)(255 * (1 - modff(u, &iptr)));
746 ab = (int)(255 * (1 - modff(v, &iptr)));
747 iru = uu + 1;
748 irv = vv + 1;
749
750 if (vv >= sh) continue;
751
752 px = *(sbuf + (vv * sw) + uu);
753
754 /* horizontal interpolate */
755 if (iru < sw) {
756 /* right pixel */
757 int px2 = *(sbuf + (vv * sw) + iru);
758 px = INTERPOLATE(px, px2, ar);
759 }
760 /* vertical interpolate */
761 if (irv < sh) {
762 /* bottom pixel */
763 int px2 = *(sbuf + (irv * sw) + uu);
764
765 /* horizontal interpolate */
766 if (iru < sw) {
767 /* bottom right pixel */
768 int px3 = *(sbuf + (irv * sw) + iru);
769 px2 = INTERPOLATE(px2, px3, ar);
770 }
771 px = INTERPOLATE(px, px2, ab);
772 }
773 uint32_t src;
774 if (matting) {
775 src = ALPHA_BLEND(px, MULTIPLY(opacity, alpha(cmp)));
776 cmp += csize;
777 } else {
778 src = ALPHA_BLEND(px, opacity);
779 }
780 *buf = src + ALPHA_BLEND(*buf, IA(src));
781 ++buf;
782
783 //Step UV horizontally
784 u += _dudx;
785 v += _dvdx;
786 //range over?
787 if ((uint32_t)v >= image->h) break;
788 }
789 }
790 }
791
792 //Step along both edges
793 _xa += _dxdya;
794 _xb += _dxdyb;
795 _ua += _dudya;
796 _va += _dvdya;
797
798 if (!region && spanIdx >= image->rle->size) break;
799
800 ++y;
801 }
802 xa = _xa;
803 xb = _xb;
804 ua = _ua;
805 va = _va;
806}
807
808
809/* This mapping algorithm is based on Mikael Kalms's. */
810static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox* region, Polygon& polygon, AASpans* aaSpans, uint8_t opacity)
811{
812 float x[3] = {polygon.vertex[0].pt.x, polygon.vertex[1].pt.x, polygon.vertex[2].pt.x};
813 float y[3] = {polygon.vertex[0].pt.y, polygon.vertex[1].pt.y, polygon.vertex[2].pt.y};
814 float u[3] = {polygon.vertex[0].uv.x, polygon.vertex[1].uv.x, polygon.vertex[2].uv.x};
815 float v[3] = {polygon.vertex[0].uv.y, polygon.vertex[1].uv.y, polygon.vertex[2].uv.y};
816
817 float off_y;
818 float dxdy[3] = {0.0f, 0.0f, 0.0f};
819 float tmp;
820
821 auto upper = false;
822
823 //Sort the vertices in ascending Y order
824 if (y[0] > y[1]) {
825 _swap(x[0], x[1], tmp);
826 _swap(y[0], y[1], tmp);
827 _swap(u[0], u[1], tmp);
828 _swap(v[0], v[1], tmp);
829 }
830 if (y[0] > y[2]) {
831 _swap(x[0], x[2], tmp);
832 _swap(y[0], y[2], tmp);
833 _swap(u[0], u[2], tmp);
834 _swap(v[0], v[2], tmp);
835 }
836 if (y[1] > y[2]) {
837 _swap(x[1], x[2], tmp);
838 _swap(y[1], y[2], tmp);
839 _swap(u[1], u[2], tmp);
840 _swap(v[1], v[2], tmp);
841 }
842
843 //Y indexes
844 int yi[3] = {(int)y[0], (int)y[1], (int)y[2]};
845
846 //Skip drawing if it's too thin to cover any pixels at all.
847 if ((yi[0] == yi[1] && yi[0] == yi[2]) || ((int) x[0] == (int) x[1] && (int) x[0] == (int) x[2])) return;
848
849 //Calculate horizontal and vertical increments for UV axes (these calcs are certainly not optimal, although they're stable (handles any dy being 0)
850 auto denom = ((x[2] - x[0]) * (y[1] - y[0]) - (x[1] - x[0]) * (y[2] - y[0]));
851
852 //Skip poly if it's an infinitely thin line
853 if (mathZero(denom)) return;
854
855 denom = 1 / denom; //Reciprocal for speeding up
856 dudx = ((u[2] - u[0]) * (y[1] - y[0]) - (u[1] - u[0]) * (y[2] - y[0])) * denom;
857 dvdx = ((v[2] - v[0]) * (y[1] - y[0]) - (v[1] - v[0]) * (y[2] - y[0])) * denom;
858 auto dudy = ((u[1] - u[0]) * (x[2] - x[0]) - (u[2] - u[0]) * (x[1] - x[0])) * denom;
859 auto dvdy = ((v[1] - v[0]) * (x[2] - x[0]) - (v[2] - v[0]) * (x[1] - x[0])) * denom;
860
861 //Calculate X-slopes along the edges
862 if (y[1] > y[0]) dxdy[0] = (x[1] - x[0]) / (y[1] - y[0]);
863 if (y[2] > y[0]) dxdy[1] = (x[2] - x[0]) / (y[2] - y[0]);
864 if (y[2] > y[1]) dxdy[2] = (x[2] - x[1]) / (y[2] - y[1]);
865
866 //Determine which side of the polygon the longer edge is on
867 auto side = (dxdy[1] > dxdy[0]) ? true : false;
868
869 if (mathEqual(y[0], y[1])) side = x[0] > x[1];
870 if (mathEqual(y[1], y[2])) side = x[2] > x[1];
871
872 auto regionTop = region ? region->min.y : image->rle->spans->y; //Normal Image or Rle Image?
873 auto compositing = _compositing(surface); //Composition required
874 auto blending = _blending(surface); //Blending required
875
876 //Longer edge is on the left side
877 if (!side) {
878 //Calculate slopes along left edge
879 dxdya = dxdy[1];
880 dudya = dxdya * dudx + dudy;
881 dvdya = dxdya * dvdx + dvdy;
882
883 //Perform subpixel pre-stepping along left edge
884 auto dy = 1.0f - (y[0] - yi[0]);
885 xa = x[0] + dy * dxdya;
886 ua = u[0] + dy * dudya;
887 va = v[0] + dy * dvdya;
888
889 //Draw upper segment if possibly visible
890 if (yi[0] < yi[1]) {
891 off_y = y[0] < regionTop ? (regionTop - y[0]) : 0;
892 xa += (off_y * dxdya);
893 ua += (off_y * dudya);
894 va += (off_y * dvdya);
895
896 // Set right edge X-slope and perform subpixel pre-stepping
897 dxdyb = dxdy[0];
898 xb = x[0] + dy * dxdyb + (off_y * dxdyb);
899
900 if (compositing) {
901 if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, true);
902 else _rasterMaskedPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, 1);
903 } else if (blending) {
904 _rasterBlendingPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity);
905 } else {
906 _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, false);
907 }
908 upper = true;
909 }
910 //Draw lower segment if possibly visible
911 if (yi[1] < yi[2]) {
912 off_y = y[1] < regionTop ? (regionTop - y[1]) : 0;
913 if (!upper) {
914 xa += (off_y * dxdya);
915 ua += (off_y * dudya);
916 va += (off_y * dvdya);
917 }
918 // Set right edge X-slope and perform subpixel pre-stepping
919 dxdyb = dxdy[2];
920 xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb);
921 if (compositing) {
922 if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, true);
923 else _rasterMaskedPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, 2);
924 } else if (blending) {
925 _rasterBlendingPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity);
926 } else {
927 _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, false);
928 }
929 }
930 //Longer edge is on the right side
931 } else {
932 //Set right edge X-slope and perform subpixel pre-stepping
933 dxdyb = dxdy[1];
934 auto dy = 1.0f - (y[0] - yi[0]);
935 xb = x[0] + dy * dxdyb;
936
937 //Draw upper segment if possibly visible
938 if (yi[0] < yi[1]) {
939 off_y = y[0] < regionTop ? (regionTop - y[0]) : 0;
940 xb += (off_y *dxdyb);
941
942 // Set slopes along left edge and perform subpixel pre-stepping
943 dxdya = dxdy[0];
944 dudya = dxdya * dudx + dudy;
945 dvdya = dxdya * dvdx + dvdy;
946
947 xa = x[0] + dy * dxdya + (off_y * dxdya);
948 ua = u[0] + dy * dudya + (off_y * dudya);
949 va = v[0] + dy * dvdya + (off_y * dvdya);
950
951 if (compositing) {
952 if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, true);
953 else _rasterMaskedPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, 3);
954 } else if (blending) {
955 _rasterBlendingPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity);
956 } else {
957 _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], aaSpans, opacity, false);
958 }
959 upper = true;
960 }
961 //Draw lower segment if possibly visible
962 if (yi[1] < yi[2]) {
963 off_y = y[1] < regionTop ? (regionTop - y[1]) : 0;
964 if (!upper) xb += (off_y *dxdyb);
965
966 // Set slopes along left edge and perform subpixel pre-stepping
967 dxdya = dxdy[2];
968 dudya = dxdya * dudx + dudy;
969 dvdya = dxdya * dvdx + dvdy;
970 dy = 1 - (y[1] - yi[1]);
971 xa = x[1] + dy * dxdya + (off_y * dxdya);
972 ua = u[1] + dy * dudya + (off_y * dudya);
973 va = v[1] + dy * dvdya + (off_y * dvdya);
974
975 if (compositing) {
976 if (_matting(surface)) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, true);
977 else _rasterMaskedPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, 4);
978 } else if (blending) {
979 _rasterBlendingPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity);
980 } else {
981 _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], aaSpans, opacity, false);
982 }
983 }
984 }
985}
986
987
988static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwBBox* region)
989{
990 auto yStart = static_cast<int32_t>(ymin);
991 auto yEnd = static_cast<int32_t>(ymax);
992
993 if (!_arrange(image, region, yStart, yEnd)) return nullptr;
994
995 auto aaSpans = static_cast<AASpans*>(malloc(sizeof(AASpans)));
996 aaSpans->yStart = yStart;
997 aaSpans->yEnd = yEnd;
998
999 //Initialize X range
1000 auto height = yEnd - yStart;
1001
1002 aaSpans->lines = static_cast<AALine*>(calloc(height, sizeof(AALine)));
1003
1004 for (int32_t i = 0; i < height; i++) {
1005 aaSpans->lines[i].x[0] = INT32_MAX;
1006 aaSpans->lines[i].x[1] = INT32_MIN;
1007 }
1008 return aaSpans;
1009}
1010
1011
1012static void _calcIrregularCoverage(AALine* lines, int32_t eidx, int32_t y, int32_t diagonal, int32_t edgeDist, bool reverse)
1013{
1014 if (eidx == 1) reverse = !reverse;
1015 int32_t coverage = (255 / (diagonal + 2));
1016 int32_t tmp;
1017 for (int32_t ry = 0; ry < (diagonal + 2); ry++) {
1018 tmp = y - ry - edgeDist;
1019 if (tmp < 0) return;
1020 lines[tmp].length[eidx] = 1;
1021 if (reverse) lines[tmp].coverage[eidx] = 255 - (coverage * ry);
1022 else lines[tmp].coverage[eidx] = (coverage * ry);
1023 }
1024}
1025
1026
1027static void _calcVertCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t rewind, bool reverse)
1028{
1029 if (eidx == 1) reverse = !reverse;
1030 int32_t coverage = (255 / (rewind + 1));
1031 int32_t tmp;
1032 for (int ry = 1; ry < (rewind + 1); ry++) {
1033 tmp = y - ry;
1034 if (tmp < 0) return;
1035 lines[tmp].length[eidx] = 1;
1036 if (reverse) lines[tmp].coverage[eidx] = (255 - (coverage * ry));
1037 else lines[tmp].coverage[eidx] = (coverage * ry);
1038 }
1039}
1040
1041
1042static void _calcHorizCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t x, int32_t x2)
1043{
1044 if (lines[y].length[eidx] < abs(x - x2)) {
1045 lines[y].length[eidx] = abs(x - x2);
1046 lines[y].coverage[eidx] = (255 / (lines[y].length[eidx] + 1));
1047 }
1048}
1049
1050
1051/*
1052 * This Anti-Aliasing mechanism is originated from Hermet Park's idea.
1053 * To understand this AA logic, you can refer this page:
1054 * www.hermet.pe.kr/122 (hermetpark@gmail.com)
1055*/
1056static void _calcAAEdge(AASpans *aaSpans, int32_t eidx)
1057{
1058//Previous edge direction:
1059#define DirOutHor 0x0011
1060#define DirOutVer 0x0001
1061#define DirInHor 0x0010
1062#define DirInVer 0x0000
1063#define DirNone 0x1000
1064
1065#define PUSH_VERTEX() \
1066 do { \
1067 pEdge.x = lines[y].x[eidx]; \
1068 pEdge.y = y; \
1069 ptx[0] = tx[0]; \
1070 ptx[1] = tx[1]; \
1071 } while (0)
1072
1073 int32_t y = 0;
1074 SwPoint pEdge = {-1, -1}; //previous edge point
1075 SwPoint edgeDiff = {0, 0}; //temporary used for point distance
1076
1077 /* store bigger to tx[0] between prev and current edge's x positions. */
1078 int32_t tx[2] = {0, 0};
1079 /* back up prev tx values */
1080 int32_t ptx[2] = {0, 0};
1081 int32_t diagonal = 0; //straight diagonal pixels count
1082
1083 auto yStart = aaSpans->yStart;
1084 auto yEnd = aaSpans->yEnd;
1085 auto lines = aaSpans->lines;
1086
1087 int32_t prevDir = DirNone;
1088 int32_t curDir = DirNone;
1089
1090 yEnd -= yStart;
1091
1092 //Start Edge
1093 if (y < yEnd) {
1094 pEdge.x = lines[y].x[eidx];
1095 pEdge.y = y;
1096 }
1097
1098 //Calculates AA Edges
1099 for (y++; y < yEnd; y++) {
1100 //Ready tx
1101 if (eidx == 0) {
1102 tx[0] = pEdge.x;
1103 tx[1] = lines[y].x[0];
1104 } else {
1105 tx[0] = lines[y].x[1];
1106 tx[1] = pEdge.x;
1107 }
1108 edgeDiff.x = (tx[0] - tx[1]);
1109 edgeDiff.y = (y - pEdge.y);
1110
1111 //Confirm current edge direction
1112 if (edgeDiff.x > 0) {
1113 if (edgeDiff.y == 1) curDir = DirOutHor;
1114 else curDir = DirOutVer;
1115 } else if (edgeDiff.x < 0) {
1116 if (edgeDiff.y == 1) curDir = DirInHor;
1117 else curDir = DirInVer;
1118 } else curDir = DirNone;
1119
1120 //straight diagonal increase
1121 if ((curDir == prevDir) && (y < yEnd)) {
1122 if ((abs(edgeDiff.x) == 1) && (edgeDiff.y == 1)) {
1123 ++diagonal;
1124 PUSH_VERTEX();
1125 continue;
1126 }
1127 }
1128
1129 switch (curDir) {
1130 case DirOutHor: {
1131 _calcHorizCoverage(lines, eidx, y, tx[0], tx[1]);
1132 if (diagonal > 0) {
1133 _calcIrregularCoverage(lines, eidx, y, diagonal, 0, true);
1134 diagonal = 0;
1135 }
1136 /* Increment direction is changed: Outside Vertical -> Outside Horizontal */
1137 if (prevDir == DirOutVer) _calcHorizCoverage(lines, eidx, pEdge.y, ptx[0], ptx[1]);
1138
1139 //Trick, but fine-tunning!
1140 if (y == 1) _calcHorizCoverage(lines, eidx, pEdge.y, tx[0], tx[1]);
1141 PUSH_VERTEX();
1142 }
1143 break;
1144 case DirOutVer: {
1145 _calcVertCoverage(lines, eidx, y, edgeDiff.y, true);
1146 if (diagonal > 0) {
1147 _calcIrregularCoverage(lines, eidx, y, diagonal, edgeDiff.y, false);
1148 diagonal = 0;
1149 }
1150 /* Increment direction is changed: Outside Horizontal -> Outside Vertical */
1151 if (prevDir == DirOutHor) _calcHorizCoverage(lines, eidx, pEdge.y, ptx[0], ptx[1]);
1152 PUSH_VERTEX();
1153 }
1154 break;
1155 case DirInHor: {
1156 _calcHorizCoverage(lines, eidx, (y - 1), tx[0], tx[1]);
1157 if (diagonal > 0) {
1158 _calcIrregularCoverage(lines, eidx, y, diagonal, 0, false);
1159 diagonal = 0;
1160 }
1161 /* Increment direction is changed: Outside Horizontal -> Inside Horizontal */
1162 if (prevDir == DirOutHor) _calcHorizCoverage(lines, eidx, pEdge.y, ptx[0], ptx[1]);
1163 PUSH_VERTEX();
1164 }
1165 break;
1166 case DirInVer: {
1167 _calcVertCoverage(lines, eidx, y, edgeDiff.y, false);
1168 if (prevDir == DirOutHor) edgeDiff.y -= 1; //Weird, fine tuning?????????????????????
1169 if (diagonal > 0) {
1170 _calcIrregularCoverage(lines, eidx, y, diagonal, edgeDiff.y, true);
1171 diagonal = 0;
1172 }
1173 /* Increment direction is changed: Outside Horizontal -> Inside Vertical */
1174 if (prevDir == DirOutHor) _calcHorizCoverage(lines, eidx, pEdge.y, ptx[0], ptx[1]);
1175 PUSH_VERTEX();
1176 }
1177 break;
1178 }
1179 if (curDir != DirNone) prevDir = curDir;
1180 }
1181
1182 //leftovers...?
1183 if ((edgeDiff.y == 1) && (edgeDiff.x != 0)) {
1184 if (y >= yEnd) y = (yEnd - 1);
1185 _calcHorizCoverage(lines, eidx, y - 1, ptx[0], ptx[1]);
1186 _calcHorizCoverage(lines, eidx, y, tx[0], tx[1]);
1187 } else {
1188 ++y;
1189 if (y > yEnd) y = yEnd;
1190 _calcVertCoverage(lines, eidx, y, (edgeDiff.y + 1), (prevDir & 0x00000001));
1191 }
1192}
1193
1194
1195static bool _apply(SwSurface* surface, AASpans* aaSpans)
1196{
1197 auto y = aaSpans->yStart;
1198 uint32_t pixel;
1199 uint32_t* dst;
1200 int32_t pos;
1201
1202 //left side
1203 _calcAAEdge(aaSpans, 0);
1204 //right side
1205 _calcAAEdge(aaSpans, 1);
1206
1207 while (y < aaSpans->yEnd) {
1208 auto line = &aaSpans->lines[y - aaSpans->yStart];
1209 auto width = line->x[1] - line->x[0];
1210 if (width > 0) {
1211 auto offset = y * surface->stride;
1212
1213 //Left edge
1214 dst = surface->buf32 + (offset + line->x[0]);
1215 if (line->x[0] > 1) pixel = *(dst - 1);
1216 else pixel = *dst;
1217
1218 pos = 1;
1219 while (pos <= line->length[0]) {
1220 *dst = INTERPOLATE(*dst, pixel, line->coverage[0] * pos);
1221 ++dst;
1222 ++pos;
1223 }
1224
1225 //Right edge
1226 dst = surface->buf32 + (offset + line->x[1] - 1);
1227 if (line->x[1] < (int32_t)(surface->w - 1)) pixel = *(dst + 1);
1228 else pixel = *dst;
1229
1230 pos = width;
1231 while ((int32_t)(width - line->length[1]) < pos) {
1232 *dst = INTERPOLATE(*dst, pixel, 255 - (line->coverage[1] * (line->length[1] - (width - pos))));
1233 --dst;
1234 --pos;
1235 }
1236 }
1237 y++;
1238 }
1239
1240 free(aaSpans->lines);
1241 free(aaSpans);
1242
1243 return true;
1244}
1245
1246
1247/*
1248 2 triangles constructs 1 mesh.
1249 below figure illustrates vert[4] index info.
1250 If you need better quality, please divide a mesh by more number of triangles.
1251
1252 0 -- 1
1253 | / |
1254 | / |
1255 3 -- 2
1256*/
1257static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint8_t opacity)
1258{
1259 //Exceptions: No dedicated drawing area?
1260 if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
1261
1262 /* Prepare vertices.
1263 shift XY coordinates to match the sub-pixeling technique. */
1264 Vertex vertices[4];
1265 vertices[0] = {{0.0f, 0.0f}, {0.0f, 0.0f}};
1266 vertices[1] = {{float(image->w), 0.0f}, {float(image->w), 0.0f}};
1267 vertices[2] = {{float(image->w), float(image->h)}, {float(image->w), float(image->h)}};
1268 vertices[3] = {{0.0f, float(image->h)}, {0.0f, float(image->h)}};
1269
1270 float ys = FLT_MAX, ye = -1.0f;
1271 for (int i = 0; i < 4; i++) {
1272 mathMultiply(&vertices[i].pt, transform);
1273
1274 if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
1275 if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
1276 }
1277
1278 auto aaSpans = _AASpans(ys, ye, image, region);
1279 if (!aaSpans) return true;
1280
1281 Polygon polygon;
1282
1283 //Draw the first polygon
1284 polygon.vertex[0] = vertices[0];
1285 polygon.vertex[1] = vertices[1];
1286 polygon.vertex[2] = vertices[3];
1287
1288 _rasterPolygonImage(surface, image, region, polygon, aaSpans, opacity);
1289
1290 //Draw the second polygon
1291 polygon.vertex[0] = vertices[1];
1292 polygon.vertex[1] = vertices[2];
1293 polygon.vertex[2] = vertices[3];
1294
1295 _rasterPolygonImage(surface, image, region, polygon, aaSpans, opacity);
1296
1297 return _apply(surface, aaSpans);
1298}
1299
1300
1301/*
1302 Provide any number of triangles to draw a mesh using the supplied image.
1303 Indexes are not used, so each triangle (Polygon) vertex has to be defined, even if they copy the previous one.
1304 Example:
1305
1306 0 -- 1 0 -- 1 0
1307 | / | --> | / / |
1308 | / | | / / |
1309 2 -- 3 2 1 -- 2
1310
1311 Should provide two Polygons, one for each triangle.
1312 // TODO: region?
1313*/
1314static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint8_t opacity)
1315{
1316 //Exceptions: No dedicated drawing area?
1317 if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false;
1318
1319 // Step polygons once to transform
1320 auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * mesh->triangleCnt);
1321 float ys = FLT_MAX, ye = -1.0f;
1322 for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
1323 transformedTris[i] = mesh->triangles[i];
1324 mathMultiply(&transformedTris[i].vertex[0].pt, transform);
1325 mathMultiply(&transformedTris[i].vertex[1].pt, transform);
1326 mathMultiply(&transformedTris[i].vertex[2].pt, transform);
1327
1328 if (transformedTris[i].vertex[0].pt.y < ys) ys = transformedTris[i].vertex[0].pt.y;
1329 else if (transformedTris[i].vertex[0].pt.y > ye) ye = transformedTris[i].vertex[0].pt.y;
1330 if (transformedTris[i].vertex[1].pt.y < ys) ys = transformedTris[i].vertex[1].pt.y;
1331 else if (transformedTris[i].vertex[1].pt.y > ye) ye = transformedTris[i].vertex[1].pt.y;
1332 if (transformedTris[i].vertex[2].pt.y < ys) ys = transformedTris[i].vertex[2].pt.y;
1333 else if (transformedTris[i].vertex[2].pt.y > ye) ye = transformedTris[i].vertex[2].pt.y;
1334
1335 // Convert normalized UV coordinates to image coordinates
1336 transformedTris[i].vertex[0].uv.x *= (float)image->w;
1337 transformedTris[i].vertex[0].uv.y *= (float)image->h;
1338 transformedTris[i].vertex[1].uv.x *= (float)image->w;
1339 transformedTris[i].vertex[1].uv.y *= (float)image->h;
1340 transformedTris[i].vertex[2].uv.x *= (float)image->w;
1341 transformedTris[i].vertex[2].uv.y *= (float)image->h;
1342 }
1343
1344 // Get AA spans and step polygons again to draw
1345 auto aaSpans = _AASpans(ys, ye, image, region);
1346 if (aaSpans) {
1347 for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
1348 _rasterPolygonImage(surface, image, region, transformedTris[i], aaSpans, opacity);
1349 }
1350 // Apply to surface (note: frees the AA spans)
1351 _apply(surface, aaSpans);
1352 }
1353 free(transformedTris);
1354
1355 return true;
1356}
1357