btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / headers / libs / agg / agg_scanline_boolean_algebra.h
blobbc2e9c9d51fa84be5978ac09f654ddf4eb9033cd
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 // mcseemagg@yahoo.com
13 // http://www.antigrain.com
14 //----------------------------------------------------------------------------
16 #ifndef AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
17 #define AGG_SCANLINE_BOOLEAN_ALGEBRA_INCLUDED
19 #include <stdlib.h>
20 #include <math.h>
21 #include "agg_basics.h"
24 namespace agg
27 //-----------------------------------------------sbool_combine_spans_bin
28 // Functor.
29 // Combine two binary encoded spans, i.e., when we don't have any
30 // anti-aliasing information, but only X and Length. The function
31 // is compatible with any type of scanlines.
32 //----------------
33 template<class Scanline1,
34 class Scanline2,
35 class Scanline>
36 struct sbool_combine_spans_bin
38 void operator () (const typename Scanline1::const_iterator&,
39 const typename Scanline2::const_iterator&,
40 int x, unsigned len,
41 Scanline& sl) const
43 sl.add_span(x, len, cover_full);
49 //---------------------------------------------sbool_combine_spans_empty
50 // Functor.
51 // Combine two spans as empty ones. The functor does nothing
52 // and is used to XOR binary spans.
53 //----------------
54 template<class Scanline1,
55 class Scanline2,
56 class Scanline>
57 struct sbool_combine_spans_empty
59 void operator () (const typename Scanline1::const_iterator&,
60 const typename Scanline2::const_iterator&,
61 int, unsigned,
62 Scanline&) const
68 //--------------------------------------------------sbool_add_span_empty
69 // Functor.
70 // Add nothing. Used in conbine_shapes_sub
71 //----------------
72 template<class Scanline1,
73 class Scanline>
74 struct sbool_add_span_empty
76 void operator () (const typename Scanline1::const_iterator&,
77 int, unsigned,
78 Scanline&) const
83 //----------------------------------------------------sbool_add_span_bin
84 // Functor.
85 // Add a binary span
86 //----------------
87 template<class Scanline1,
88 class Scanline>
89 struct sbool_add_span_bin
91 void operator () (const typename Scanline1::const_iterator&,
92 int x, unsigned len,
93 Scanline& sl) const
95 sl.add_span(x, len, cover_full);
102 //-----------------------------------------------------sbool_add_span_aa
103 // Functor.
104 // Add an anti-aliased span
105 // anti-aliasing information, but only X and Length. The function
106 // is compatible with any type of scanlines.
107 //----------------
108 template<class Scanline1,
109 class Scanline>
110 struct sbool_add_span_aa
112 void operator () (const typename Scanline1::const_iterator& span,
113 int x, unsigned len,
114 Scanline& sl) const
116 if(span->len < 0)
118 sl.add_span(x, len, *span->covers);
120 else
121 if(span->len > 0)
123 const typename Scanline1::cover_type* covers = span->covers;
124 if(span->x < x) covers += x - span->x;
125 sl.add_cells(x, len, covers);
133 //----------------------------------------------sbool_intersect_spans_aa
134 // Functor.
135 // Intersect two spans preserving the anti-aliasing information.
136 // The result is added to the "sl" scanline.
137 //------------------
138 template<class Scanline1,
139 class Scanline2,
140 class Scanline,
141 unsigned CoverShift = cover_shift>
142 struct sbool_intersect_spans_aa
144 enum cover_scale_e
146 cover_shift = CoverShift,
147 cover_size = 1 << cover_shift,
148 cover_mask = cover_size - 1,
149 cover_full = cover_mask
153 void operator () (const typename Scanline1::const_iterator& span1,
154 const typename Scanline2::const_iterator& span2,
155 int x, unsigned len,
156 Scanline& sl) const
158 unsigned cover;
159 const typename Scanline1::cover_type* covers1;
160 const typename Scanline2::cover_type* covers2;
162 // Calculate the operation code and choose the
163 // proper combination algorithm.
164 // 0 = Both spans are of AA type
165 // 1 = span1 is solid, span2 is AA
166 // 2 = span1 is AA, span2 is solid
167 // 3 = Both spans are of solid type
168 //-----------------
169 switch((span1->len < 0) | ((span2->len < 0) << 1))
171 case 0: // Both are AA spans
172 covers1 = span1->covers;
173 covers2 = span2->covers;
174 if(span1->x < x) covers1 += x - span1->x;
175 if(span2->x < x) covers2 += x - span2->x;
178 cover = *covers1++ * *covers2++;
179 sl.add_cell(x++,
180 (cover == cover_full * cover_full) ?
181 cover_full :
182 (cover >> cover_shift));
184 while(--len);
185 break;
187 case 1: // span1 is solid, span2 is AA
188 covers2 = span2->covers;
189 if(span2->x < x) covers2 += x - span2->x;
190 if(*(span1->covers) == cover_full)
192 sl.add_cells(x, len, covers2);
194 else
198 cover = *(span1->covers) * *covers2++;
199 sl.add_cell(x++,
200 (cover == cover_full * cover_full) ?
201 cover_full :
202 (cover >> cover_shift));
204 while(--len);
206 break;
208 case 2: // span1 is AA, span2 is solid
209 covers1 = span1->covers;
210 if(span1->x < x) covers1 += x - span1->x;
211 if(*(span2->covers) == cover_full)
213 sl.add_cells(x, len, covers1);
215 else
219 cover = *covers1++ * *(span2->covers);
220 sl.add_cell(x++,
221 (cover == cover_full * cover_full) ?
222 cover_full :
223 (cover >> cover_shift));
225 while(--len);
227 break;
229 case 3: // Both are solid spans
230 cover = *(span1->covers) * *(span2->covers);
231 sl.add_span(x, len,
232 (cover == cover_full * cover_full) ?
233 cover_full :
234 (cover >> cover_shift));
235 break;
245 //--------------------------------------------------sbool_unite_spans_aa
246 // Functor.
247 // Unite two spans preserving the anti-aliasing information.
248 // The result is added to the "sl" scanline.
249 //------------------
250 template<class Scanline1,
251 class Scanline2,
252 class Scanline,
253 unsigned CoverShift = cover_shift>
254 struct sbool_unite_spans_aa
256 enum cover_scale_e
258 cover_shift = CoverShift,
259 cover_size = 1 << cover_shift,
260 cover_mask = cover_size - 1,
261 cover_full = cover_mask
265 void operator () (const typename Scanline1::const_iterator& span1,
266 const typename Scanline2::const_iterator& span2,
267 int x, unsigned len,
268 Scanline& sl) const
270 unsigned cover;
271 const typename Scanline1::cover_type* covers1;
272 const typename Scanline2::cover_type* covers2;
274 // Calculate the operation code and choose the
275 // proper combination algorithm.
276 // 0 = Both spans are of AA type
277 // 1 = span1 is solid, span2 is AA
278 // 2 = span1 is AA, span2 is solid
279 // 3 = Both spans are of solid type
280 //-----------------
281 switch((span1->len < 0) | ((span2->len < 0) << 1))
283 case 0: // Both are AA spans
284 covers1 = span1->covers;
285 covers2 = span2->covers;
286 if(span1->x < x) covers1 += x - span1->x;
287 if(span2->x < x) covers2 += x - span2->x;
290 cover = cover_mask * cover_mask -
291 (cover_mask - *covers1++) *
292 (cover_mask - *covers2++);
293 sl.add_cell(x++,
294 (cover == cover_full * cover_full) ?
295 cover_full :
296 (cover >> cover_shift));
298 while(--len);
299 break;
301 case 1: // span1 is solid, span2 is AA
302 covers2 = span2->covers;
303 if(span2->x < x) covers2 += x - span2->x;
304 if(*(span1->covers) == cover_full)
306 sl.add_span(x, len, cover_full);
308 else
312 cover = cover_mask * cover_mask -
313 (cover_mask - *(span1->covers)) *
314 (cover_mask - *covers2++);
315 sl.add_cell(x++,
316 (cover == cover_full * cover_full) ?
317 cover_full :
318 (cover >> cover_shift));
320 while(--len);
322 break;
324 case 2: // span1 is AA, span2 is solid
325 covers1 = span1->covers;
326 if(span1->x < x) covers1 += x - span1->x;
327 if(*(span2->covers) == cover_full)
329 sl.add_span(x, len, cover_full);
331 else
335 cover = cover_mask * cover_mask -
336 (cover_mask - *covers1++) *
337 (cover_mask - *(span2->covers));
338 sl.add_cell(x++,
339 (cover == cover_full * cover_full) ?
340 cover_full :
341 (cover >> cover_shift));
343 while(--len);
345 break;
347 case 3: // Both are solid spans
348 cover = cover_mask * cover_mask -
349 (cover_mask - *(span1->covers)) *
350 (cover_mask - *(span2->covers));
351 sl.add_span(x, len,
352 (cover == cover_full * cover_full) ?
353 cover_full :
354 (cover >> cover_shift));
355 break;
361 //---------------------------------------------sbool_xor_formula_linear
362 template<unsigned CoverShift = cover_shift>
363 struct sbool_xor_formula_linear
365 enum cover_scale_e
367 cover_shift = CoverShift,
368 cover_size = 1 << cover_shift,
369 cover_mask = cover_size - 1
372 static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
374 unsigned cover = a + b;
375 if(cover > cover_mask) cover = cover_mask + cover_mask - cover;
376 return cover;
381 //---------------------------------------------sbool_xor_formula_saddle
382 template<unsigned CoverShift = cover_shift>
383 struct sbool_xor_formula_saddle
385 enum cover_scale_e
387 cover_shift = CoverShift,
388 cover_size = 1 << cover_shift,
389 cover_mask = cover_size - 1
392 static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
394 unsigned k = a * b;
395 if(k == cover_mask * cover_mask) return 0;
397 a = (cover_mask * cover_mask - (a << cover_shift) + k) >> cover_shift;
398 b = (cover_mask * cover_mask - (b << cover_shift) + k) >> cover_shift;
399 return cover_mask - ((a * b) >> cover_shift);
404 //-------------------------------------------sbool_xor_formula_abs_diff
405 struct sbool_xor_formula_abs_diff
407 static AGG_INLINE unsigned calculate(unsigned a, unsigned b)
409 return unsigned(abs(int(a) - int(b)));
415 //----------------------------------------------------sbool_xor_spans_aa
416 // Functor.
417 // XOR two spans preserving the anti-aliasing information.
418 // The result is added to the "sl" scanline.
419 //------------------
420 template<class Scanline1,
421 class Scanline2,
422 class Scanline,
423 class XorFormula,
424 unsigned CoverShift = cover_shift>
425 struct sbool_xor_spans_aa
427 enum cover_scale_e
429 cover_shift = CoverShift,
430 cover_size = 1 << cover_shift,
431 cover_mask = cover_size - 1,
432 cover_full = cover_mask
436 void operator () (const typename Scanline1::const_iterator& span1,
437 const typename Scanline2::const_iterator& span2,
438 int x, unsigned len,
439 Scanline& sl) const
441 unsigned cover;
442 const typename Scanline1::cover_type* covers1;
443 const typename Scanline2::cover_type* covers2;
445 // Calculate the operation code and choose the
446 // proper combination algorithm.
447 // 0 = Both spans are of AA type
448 // 1 = span1 is solid, span2 is AA
449 // 2 = span1 is AA, span2 is solid
450 // 3 = Both spans are of solid type
451 //-----------------
452 switch((span1->len < 0) | ((span2->len < 0) << 1))
454 case 0: // Both are AA spans
455 covers1 = span1->covers;
456 covers2 = span2->covers;
457 if(span1->x < x) covers1 += x - span1->x;
458 if(span2->x < x) covers2 += x - span2->x;
461 cover = XorFormula::calculate(*covers1++, *covers2++);
462 if(cover) sl.add_cell(x, cover);
463 ++x;
465 while(--len);
466 break;
468 case 1: // span1 is solid, span2 is AA
469 covers2 = span2->covers;
470 if(span2->x < x) covers2 += x - span2->x;
473 cover = XorFormula::calculate(*(span1->covers), *covers2++);
474 if(cover) sl.add_cell(x, cover);
475 ++x;
477 while(--len);
478 break;
480 case 2: // span1 is AA, span2 is solid
481 covers1 = span1->covers;
482 if(span1->x < x) covers1 += x - span1->x;
485 cover = XorFormula::calculate(*covers1++, *(span2->covers));
486 if(cover) sl.add_cell(x, cover);
487 ++x;
489 while(--len);
490 break;
492 case 3: // Both are solid spans
493 cover = XorFormula::calculate(*(span1->covers), *(span2->covers));
494 if(cover) sl.add_span(x, len, cover);
495 break;
505 //-----------------------------------------------sbool_subtract_spans_aa
506 // Functor.
507 // Unite two spans preserving the anti-aliasing information.
508 // The result is added to the "sl" scanline.
509 //------------------
510 template<class Scanline1,
511 class Scanline2,
512 class Scanline,
513 unsigned CoverShift = cover_shift>
514 struct sbool_subtract_spans_aa
516 enum cover_scale_e
518 cover_shift = CoverShift,
519 cover_size = 1 << cover_shift,
520 cover_mask = cover_size - 1,
521 cover_full = cover_mask
525 void operator () (const typename Scanline1::const_iterator& span1,
526 const typename Scanline2::const_iterator& span2,
527 int x, unsigned len,
528 Scanline& sl) const
530 unsigned cover;
531 const typename Scanline1::cover_type* covers1;
532 const typename Scanline2::cover_type* covers2;
534 // Calculate the operation code and choose the
535 // proper combination algorithm.
536 // 0 = Both spans are of AA type
537 // 1 = span1 is solid, span2 is AA
538 // 2 = span1 is AA, span2 is solid
539 // 3 = Both spans are of solid type
540 //-----------------
541 switch((span1->len < 0) | ((span2->len < 0) << 1))
543 case 0: // Both are AA spans
544 covers1 = span1->covers;
545 covers2 = span2->covers;
546 if(span1->x < x) covers1 += x - span1->x;
547 if(span2->x < x) covers2 += x - span2->x;
550 cover = *covers1++ * (cover_mask - *covers2++);
551 if(cover)
553 sl.add_cell(x,
554 (cover == cover_full * cover_full) ?
555 cover_full :
556 (cover >> cover_shift));
558 ++x;
560 while(--len);
561 break;
563 case 1: // span1 is solid, span2 is AA
564 covers2 = span2->covers;
565 if(span2->x < x) covers2 += x - span2->x;
568 cover = *(span1->covers) * (cover_mask - *covers2++);
569 if(cover)
571 sl.add_cell(x,
572 (cover == cover_full * cover_full) ?
573 cover_full :
574 (cover >> cover_shift));
576 ++x;
578 while(--len);
579 break;
581 case 2: // span1 is AA, span2 is solid
582 covers1 = span1->covers;
583 if(span1->x < x) covers1 += x - span1->x;
584 if(*(span2->covers) != cover_full)
588 cover = *covers1++ * (cover_mask - *(span2->covers));
589 if(cover)
591 sl.add_cell(x,
592 (cover == cover_full * cover_full) ?
593 cover_full :
594 (cover >> cover_shift));
596 ++x;
598 while(--len);
600 break;
602 case 3: // Both are solid spans
603 cover = *(span1->covers) * (cover_mask - *(span2->covers));
604 if(cover)
606 sl.add_span(x, len,
607 (cover == cover_full * cover_full) ?
608 cover_full :
609 (cover >> cover_shift));
611 break;
621 //--------------------------------------------sbool_add_spans_and_render
622 template<class Scanline1,
623 class Scanline,
624 class Renderer,
625 class AddSpanFunctor>
626 void sbool_add_spans_and_render(const Scanline1& sl1,
627 Scanline& sl,
628 Renderer& ren,
629 AddSpanFunctor add_span)
631 sl.reset_spans();
632 typename Scanline1::const_iterator span = sl1.begin();
633 unsigned num_spans = sl1.num_spans();
634 for(;;)
636 add_span(span, span->x, abs((int)span->len), sl);
637 if(--num_spans == 0) break;
638 ++span;
640 sl.finalize(sl1.y());
641 ren.render(sl);
650 //---------------------------------------------sbool_intersect_scanlines
651 // Intersect two scanlines, "sl1" and "sl2" and generate a new "sl" one.
652 // The combine_spans functor can be of type sbool_combine_spans_bin or
653 // sbool_intersect_spans_aa. First is a general functor to combine
654 // two spans without Anti-Aliasing, the second preserves the AA
655 // information, but works slower
657 template<class Scanline1,
658 class Scanline2,
659 class Scanline,
660 class CombineSpansFunctor>
661 void sbool_intersect_scanlines(const Scanline1& sl1,
662 const Scanline2& sl2,
663 Scanline& sl,
664 CombineSpansFunctor combine_spans)
666 sl.reset_spans();
668 unsigned num1 = sl1.num_spans();
669 if(num1 == 0) return;
671 unsigned num2 = sl2.num_spans();
672 if(num2 == 0) return;
674 typename Scanline1::const_iterator span1 = sl1.begin();
675 typename Scanline2::const_iterator span2 = sl2.begin();
677 while(num1 && num2)
679 int xb1 = span1->x;
680 int xb2 = span2->x;
681 int xe1 = xb1 + abs((int)span1->len) - 1;
682 int xe2 = xb2 + abs((int)span2->len) - 1;
684 // Determine what spans we should advance in the next step
685 // The span with the least ending X should be advanced
686 // advance_both is just an optimization when we ending
687 // coordinates are the same and we can advance both
688 //--------------
689 bool advance_span1 = xe1 < xe2;
690 bool advance_both = xe1 == xe2;
692 // Find the intersection of the spans
693 // and check if they intersect
694 //--------------
695 if(xb1 < xb2) xb1 = xb2;
696 if(xe1 > xe2) xe1 = xe2;
697 if(xb1 <= xe1)
699 combine_spans(span1, span2, xb1, xe1 - xb1 + 1, sl);
702 // Advance the spans
703 //--------------
704 if(advance_both)
706 --num1;
707 --num2;
708 if(num1) ++span1;
709 if(num2) ++span2;
711 else
713 if(advance_span1)
715 --num1;
716 if(num1) ++span1;
718 else
720 --num2;
721 if(num2) ++span2;
734 //------------------------------------------------sbool_intersect_shapes
735 // Intersect the scanline shapes. Here the "Scanline Generator"
736 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
737 // the generators, and can be of type rasterizer_scanline_aa<>.
738 // There function requires three scanline containers that can be of
739 // different types.
740 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
741 // "sl" is ised as the resulting scanline to render it.
742 // The external "sl1" and "sl2" are used only for the sake of
743 // optimization and reusing of the scanline objects.
744 // the function calls sbool_intersect_scanlines with CombineSpansFunctor
745 // as the last argument. See sbool_intersect_scanlines for details.
746 //----------
747 template<class ScanlineGen1,
748 class ScanlineGen2,
749 class Scanline1,
750 class Scanline2,
751 class Scanline,
752 class Renderer,
753 class CombineSpansFunctor>
754 void sbool_intersect_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
755 Scanline1& sl1, Scanline2& sl2,
756 Scanline& sl, Renderer& ren,
757 CombineSpansFunctor combine_spans)
759 // Prepare the scanline generators.
760 // If anyone of them doesn't contain
761 // any scanlines, then return.
762 //-----------------
763 if(!sg1.rewind_scanlines()) return;
764 if(!sg2.rewind_scanlines()) return;
766 // Get the bounding boxes
767 //----------------
768 rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
769 rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
771 // Calculate the intersection of the bounding
772 // boxes and return if they don't intersect.
773 //-----------------
774 rect_i ir = intersect_rectangles(r1, r2);
775 if(!ir.is_valid()) return;
777 // Reset the scanlines and get two first ones
778 //-----------------
779 sl.reset(ir.x1, ir.x2);
780 sl1.reset(sg1.min_x(), sg1.max_x());
781 sl2.reset(sg2.min_x(), sg2.max_x());
782 if(!sg1.sweep_scanline(sl1)) return;
783 if(!sg2.sweep_scanline(sl2)) return;
785 ren.prepare();
787 // The main loop
788 // Here we synchronize the scanlines with
789 // the same Y coordinate, ignoring all other ones.
790 // Only scanlines having the same Y-coordinate
791 // are to be combined.
792 //-----------------
793 for(;;)
795 while(sl1.y() < sl2.y())
797 if(!sg1.sweep_scanline(sl1)) return;
799 while(sl2.y() < sl1.y())
801 if(!sg2.sweep_scanline(sl2)) return;
804 if(sl1.y() == sl2.y())
806 // The Y coordinates are the same.
807 // Combine the scanlines, render if they contain any spans,
808 // and advance both generators to the next scanlines
809 //----------------------
810 sbool_intersect_scanlines(sl1, sl2, sl, combine_spans);
811 if(sl.num_spans())
813 sl.finalize(sl1.y());
814 ren.render(sl);
816 if(!sg1.sweep_scanline(sl1)) return;
817 if(!sg2.sweep_scanline(sl2)) return;
828 //-------------------------------------------------sbool_unite_scanlines
829 // Unite two scanlines, "sl1" and "sl2" and generate a new "sl" one.
830 // The combine_spans functor can be of type sbool_combine_spans_bin or
831 // sbool_intersect_spans_aa. First is a general functor to combine
832 // two spans without Anti-Aliasing, the second preserves the AA
833 // information, but works slower
835 template<class Scanline1,
836 class Scanline2,
837 class Scanline,
838 class AddSpanFunctor1,
839 class AddSpanFunctor2,
840 class CombineSpansFunctor>
841 void sbool_unite_scanlines(const Scanline1& sl1,
842 const Scanline2& sl2,
843 Scanline& sl,
844 AddSpanFunctor1 add_span1,
845 AddSpanFunctor2 add_span2,
846 CombineSpansFunctor combine_spans)
848 sl.reset_spans();
850 unsigned num1 = sl1.num_spans();
851 unsigned num2 = sl2.num_spans();
853 typename Scanline1::const_iterator span1;// = sl1.begin();
854 typename Scanline2::const_iterator span2;// = sl2.begin();
856 enum invalidation_e
858 invalid_b = 0xFFFFFFF,
859 invalid_e = invalid_b - 1
862 // Initialize the spans as invalid
863 //---------------
864 int xb1 = invalid_b;
865 int xb2 = invalid_b;
866 int xe1 = invalid_e;
867 int xe2 = invalid_e;
869 // Initialize span1 if there are spans
870 //---------------
871 if(num1)
873 span1 = sl1.begin();
874 xb1 = span1->x;
875 xe1 = xb1 + abs((int)span1->len) - 1;
876 --num1;
879 // Initialize span2 if there are spans
880 //---------------
881 if(num2)
883 span2 = sl2.begin();
884 xb2 = span2->x;
885 xe2 = xb2 + abs((int)span2->len) - 1;
886 --num2;
890 for(;;)
892 // Retrieve a new span1 if it's invalid
893 //----------------
894 if(num1 && xb1 > xe1)
896 --num1;
897 ++span1;
898 xb1 = span1->x;
899 xe1 = xb1 + abs((int)span1->len) - 1;
902 // Retrieve a new span2 if it's invalid
903 //----------------
904 if(num2 && xb2 > xe2)
906 --num2;
907 ++span2;
908 xb2 = span2->x;
909 xe2 = xb2 + abs((int)span2->len) - 1;
912 if(xb1 > xe1 && xb2 > xe2) break;
914 // Calculate the intersection
915 //----------------
916 int xb = xb1;
917 int xe = xe1;
918 if(xb < xb2) xb = xb2;
919 if(xe > xe2) xe = xe2;
920 int len = xe - xb + 1; // The length of the intersection
921 if(len > 0)
923 // The spans intersect,
924 // add the beginning of the span
925 //----------------
926 if(xb1 < xb2)
928 add_span1(span1, xb1, xb2 - xb1, sl);
929 xb1 = xb2;
931 else
932 if(xb2 < xb1)
934 add_span2(span2, xb2, xb1 - xb2, sl);
935 xb2 = xb1;
938 // Add the combination part of the spans
939 //----------------
940 combine_spans(span1, span2, xb, len, sl);
943 // Invalidate the fully processed span or both
944 //----------------
945 if(xe1 < xe2)
947 // Invalidate span1 and eat
948 // the processed part of span2
949 //--------------
950 xb1 = invalid_b;
951 xe1 = invalid_e;
952 xb2 += len;
954 else
955 if(xe2 < xe1)
957 // Invalidate span2 and eat
958 // the processed part of span1
959 //--------------
960 xb2 = invalid_b;
961 xe2 = invalid_e;
962 xb1 += len;
964 else
966 xb1 = invalid_b; // Invalidate both
967 xb2 = invalid_b;
968 xe1 = invalid_e;
969 xe2 = invalid_e;
972 else
974 // The spans do not intersect
975 //--------------
976 if(xb1 < xb2)
978 // Advance span1
979 //---------------
980 if(xb1 <= xe1)
982 add_span1(span1, xb1, xe1 - xb1 + 1, sl);
984 xb1 = invalid_b; // Invalidate
985 xe1 = invalid_e;
987 else
989 // Advance span2
990 //---------------
991 if(xb2 <= xe2)
993 add_span2(span2, xb2, xe2 - xb2 + 1, sl);
995 xb2 = invalid_b; // Invalidate
996 xe2 = invalid_e;
1005 //----------------------------------------------------sbool_unite_shapes
1006 // Unite the scanline shapes. Here the "Scanline Generator"
1007 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1008 // the generators, and can be of type rasterizer_scanline_aa<>.
1009 // There function requires three scanline containers that can be
1010 // of different type.
1011 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1012 // "sl" is ised as the resulting scanline to render it.
1013 // The external "sl1" and "sl2" are used only for the sake of
1014 // optimization and reusing of the scanline objects.
1015 // the function calls sbool_unite_scanlines with CombineSpansFunctor
1016 // as the last argument. See sbool_unite_scanlines for details.
1017 //----------
1018 template<class ScanlineGen1,
1019 class ScanlineGen2,
1020 class Scanline1,
1021 class Scanline2,
1022 class Scanline,
1023 class Renderer,
1024 class AddSpanFunctor1,
1025 class AddSpanFunctor2,
1026 class CombineSpansFunctor>
1027 void sbool_unite_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
1028 Scanline1& sl1, Scanline2& sl2,
1029 Scanline& sl, Renderer& ren,
1030 AddSpanFunctor1 add_span1,
1031 AddSpanFunctor2 add_span2,
1032 CombineSpansFunctor combine_spans)
1034 // Prepare the scanline generators.
1035 // If anyone of them doesn't contain
1036 // any scanlines, then return.
1037 //-----------------
1038 bool flag1 = sg1.rewind_scanlines();
1039 bool flag2 = sg2.rewind_scanlines();
1040 if(!flag1 && !flag2) return;
1042 // Get the bounding boxes
1043 //----------------
1044 rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
1045 rect_i r2(sg2.min_x(), sg2.min_y(), sg2.max_x(), sg2.max_y());
1047 // Calculate the union of the bounding boxes
1048 //-----------------
1049 rect_i ur(1,1,0,0);
1050 if(flag1 && flag2) ur = unite_rectangles(r1, r2);
1051 else if(flag1) ur = r1;
1052 else if(flag2) ur = r2;
1054 if(!ur.is_valid()) return;
1056 ren.prepare();
1058 // Reset the scanlines and get two first ones
1059 //-----------------
1060 sl.reset(ur.x1, ur.x2);
1061 if(flag1)
1063 sl1.reset(sg1.min_x(), sg1.max_x());
1064 flag1 = sg1.sweep_scanline(sl1);
1067 if(flag2)
1069 sl2.reset(sg2.min_x(), sg2.max_x());
1070 flag2 = sg2.sweep_scanline(sl2);
1073 // The main loop
1074 // Here we synchronize the scanlines with
1075 // the same Y coordinate.
1076 //-----------------
1077 while(flag1 || flag2)
1079 if(flag1 && flag2)
1081 if(sl1.y() == sl2.y())
1083 // The Y coordinates are the same.
1084 // Combine the scanlines, render if they contain any spans,
1085 // and advance both generators to the next scanlines
1086 //----------------------
1087 sbool_unite_scanlines(sl1, sl2, sl,
1088 add_span1, add_span2, combine_spans);
1089 if(sl.num_spans())
1091 sl.finalize(sl1.y());
1092 ren.render(sl);
1094 flag1 = sg1.sweep_scanline(sl1);
1095 flag2 = sg2.sweep_scanline(sl2);
1097 else
1099 if(sl1.y() < sl2.y())
1101 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1102 flag1 = sg1.sweep_scanline(sl1);
1104 else
1106 sbool_add_spans_and_render(sl2, sl, ren, add_span2);
1107 flag2 = sg2.sweep_scanline(sl2);
1111 else
1113 if(flag1)
1115 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1116 flag1 = sg1.sweep_scanline(sl1);
1118 if(flag2)
1120 sbool_add_spans_and_render(sl2, sl, ren, add_span2);
1121 flag2 = sg2.sweep_scanline(sl2);
1134 //-------------------------------------------------sbool_subtract_shapes
1135 // Subtract the scanline shapes, "sg1-sg2". Here the "Scanline Generator"
1136 // abstraction is used. ScanlineGen1 and ScanlineGen2 are
1137 // the generators, and can be of type rasterizer_scanline_aa<>.
1138 // There function requires three scanline containers that can be of
1139 // different types.
1140 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1141 // "sl" is ised as the resulting scanline to render it.
1142 // The external "sl1" and "sl2" are used only for the sake of
1143 // optimization and reusing of the scanline objects.
1144 // the function calls sbool_intersect_scanlines with CombineSpansFunctor
1145 // as the last argument. See combine_scanlines_sub for details.
1146 //----------
1147 template<class ScanlineGen1,
1148 class ScanlineGen2,
1149 class Scanline1,
1150 class Scanline2,
1151 class Scanline,
1152 class Renderer,
1153 class AddSpanFunctor1,
1154 class CombineSpansFunctor>
1155 void sbool_subtract_shapes(ScanlineGen1& sg1, ScanlineGen2& sg2,
1156 Scanline1& sl1, Scanline2& sl2,
1157 Scanline& sl, Renderer& ren,
1158 AddSpanFunctor1 add_span1,
1159 CombineSpansFunctor combine_spans)
1161 // Prepare the scanline generators.
1162 // Here "sg1" is master, "sg2" is slave.
1163 //-----------------
1164 if(!sg1.rewind_scanlines()) return;
1165 bool flag2 = sg2.rewind_scanlines();
1167 // Get the bounding box
1168 //----------------
1169 rect_i r1(sg1.min_x(), sg1.min_y(), sg1.max_x(), sg1.max_y());
1171 // Reset the scanlines and get two first ones
1172 //-----------------
1173 sl.reset(sg1.min_x(), sg1.max_x());
1174 sl1.reset(sg1.min_x(), sg1.max_x());
1175 sl2.reset(sg2.min_x(), sg2.max_x());
1176 if(!sg1.sweep_scanline(sl1)) return;
1178 if(flag2) flag2 = sg2.sweep_scanline(sl2);
1180 ren.prepare();
1182 // A fake span2 processor
1183 sbool_add_span_empty<Scanline2, Scanline> add_span2;
1185 // The main loop
1186 // Here we synchronize the scanlines with
1187 // the same Y coordinate, ignoring all other ones.
1188 // Only scanlines having the same Y-coordinate
1189 // are to be combined.
1190 //-----------------
1191 bool flag1 = true;
1194 // Synchronize "slave" with "master"
1195 //-----------------
1196 while(flag2 && sl2.y() < sl1.y())
1198 flag2 = sg2.sweep_scanline(sl2);
1202 if(flag2 && sl2.y() == sl1.y())
1204 // The Y coordinates are the same.
1205 // Combine the scanlines and render if they contain any spans.
1206 //----------------------
1207 sbool_unite_scanlines(sl1, sl2, sl, add_span1, add_span2, combine_spans);
1208 if(sl.num_spans())
1210 sl.finalize(sl1.y());
1211 ren.render(sl);
1214 else
1216 sbool_add_spans_and_render(sl1, sl, ren, add_span1);
1219 // Advance the "master"
1220 flag1 = sg1.sweep_scanline(sl1);
1222 while(flag1);
1231 //---------------------------------------------sbool_intersect_shapes_aa
1232 // Intersect two anti-aliased scanline shapes.
1233 // Here the "Scanline Generator" abstraction is used.
1234 // ScanlineGen1 and ScanlineGen2 are the generators, and can be of
1235 // type rasterizer_scanline_aa<>. There function requires three
1236 // scanline containers that can be of different types.
1237 // "sl1" and "sl2" are used to retrieve scanlines from the generators,
1238 // "sl" is ised as the resulting scanline to render it.
1239 // The external "sl1" and "sl2" are used only for the sake of
1240 // optimization and reusing of the scanline objects.
1241 //----------
1242 template<class ScanlineGen1,
1243 class ScanlineGen2,
1244 class Scanline1,
1245 class Scanline2,
1246 class Scanline,
1247 class Renderer>
1248 void sbool_intersect_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1249 Scanline1& sl1, Scanline2& sl2,
1250 Scanline& sl, Renderer& ren)
1252 sbool_intersect_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1253 sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
1260 //--------------------------------------------sbool_intersect_shapes_bin
1261 // Intersect two binary scanline shapes (without anti-aliasing).
1262 // See intersect_shapes_aa for more comments
1263 //----------
1264 template<class ScanlineGen1,
1265 class ScanlineGen2,
1266 class Scanline1,
1267 class Scanline2,
1268 class Scanline,
1269 class Renderer>
1270 void sbool_intersect_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1271 Scanline1& sl1, Scanline2& sl2,
1272 Scanline& sl, Renderer& ren)
1274 sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
1275 sbool_intersect_shapes(sg1, sg2, sl1, sl2, sl, ren, combine_functor);
1282 //-------------------------------------------------sbool_unite_shapes_aa
1283 // Unite two anti-aliased scanline shapes
1284 // See intersect_shapes_aa for more comments
1285 //----------
1286 template<class ScanlineGen1,
1287 class ScanlineGen2,
1288 class Scanline1,
1289 class Scanline2,
1290 class Scanline,
1291 class Renderer>
1292 void sbool_unite_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1293 Scanline1& sl1, Scanline2& sl2,
1294 Scanline& sl, Renderer& ren)
1296 sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1297 sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1298 sbool_unite_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1299 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1300 add_functor1, add_functor2, combine_functor);
1307 //------------------------------------------------sbool_unite_shapes_bin
1308 // Unite two binary scanline shapes (without anti-aliasing).
1309 // See intersect_shapes_aa for more comments
1310 //----------
1311 template<class ScanlineGen1,
1312 class ScanlineGen2,
1313 class Scanline1,
1314 class Scanline2,
1315 class Scanline,
1316 class Renderer>
1317 void sbool_unite_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1318 Scanline1& sl1, Scanline2& sl2,
1319 Scanline& sl, Renderer& ren)
1321 sbool_add_span_bin<Scanline1, Scanline> add_functor1;
1322 sbool_add_span_bin<Scanline2, Scanline> add_functor2;
1323 sbool_combine_spans_bin<Scanline1, Scanline2, Scanline> combine_functor;
1324 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1325 add_functor1, add_functor2, combine_functor);
1336 //---------------------------------------------------sbool_xor_shapes_aa
1337 // Apply eXclusive OR to two anti-aliased scanline shapes. There's
1338 // a modified "Linear" XOR used instead of classical "Saddle" one.
1339 // The reason is to have the result absolutely conststent with what
1340 // the scanline rasterizer produces.
1341 // See intersect_shapes_aa for more comments
1342 //----------
1343 template<class ScanlineGen1,
1344 class ScanlineGen2,
1345 class Scanline1,
1346 class Scanline2,
1347 class Scanline,
1348 class Renderer>
1349 void sbool_xor_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1350 Scanline1& sl1, Scanline2& sl2,
1351 Scanline& sl, Renderer& ren)
1353 sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1354 sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1355 sbool_xor_spans_aa<Scanline1, Scanline2, Scanline,
1356 sbool_xor_formula_linear<> > combine_functor;
1357 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1358 add_functor1, add_functor2, combine_functor);
1363 //------------------------------------------sbool_xor_shapes_saddle_aa
1364 // Apply eXclusive OR to two anti-aliased scanline shapes.
1365 // There's the classical "Saddle" used to calculate the
1366 // Anti-Aliasing values, that is:
1367 // a XOR b : 1-((1-a+a*b)*(1-b+a*b))
1368 // See intersect_shapes_aa for more comments
1369 //----------
1370 template<class ScanlineGen1,
1371 class ScanlineGen2,
1372 class Scanline1,
1373 class Scanline2,
1374 class Scanline,
1375 class Renderer>
1376 void sbool_xor_shapes_saddle_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1377 Scanline1& sl1, Scanline2& sl2,
1378 Scanline& sl, Renderer& ren)
1380 sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1381 sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1382 sbool_xor_spans_aa<Scanline1,
1383 Scanline2,
1384 Scanline,
1385 sbool_xor_formula_saddle<> > combine_functor;
1386 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1387 add_functor1, add_functor2, combine_functor);
1391 //--------------------------------------sbool_xor_shapes_abs_diff_aa
1392 // Apply eXclusive OR to two anti-aliased scanline shapes.
1393 // There's the absolute difference used to calculate
1394 // Anti-Aliasing values, that is:
1395 // a XOR b : abs(a-b)
1396 // See intersect_shapes_aa for more comments
1397 //----------
1398 template<class ScanlineGen1,
1399 class ScanlineGen2,
1400 class Scanline1,
1401 class Scanline2,
1402 class Scanline,
1403 class Renderer>
1404 void sbool_xor_shapes_abs_diff_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1405 Scanline1& sl1, Scanline2& sl2,
1406 Scanline& sl, Renderer& ren)
1408 sbool_add_span_aa<Scanline1, Scanline> add_functor1;
1409 sbool_add_span_aa<Scanline2, Scanline> add_functor2;
1410 sbool_xor_spans_aa<Scanline1,
1411 Scanline2,
1412 Scanline,
1413 sbool_xor_formula_abs_diff> combine_functor;
1414 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1415 add_functor1, add_functor2, combine_functor);
1420 //--------------------------------------------------sbool_xor_shapes_bin
1421 // Apply eXclusive OR to two binary scanline shapes (without anti-aliasing).
1422 // See intersect_shapes_aa for more comments
1423 //----------
1424 template<class ScanlineGen1,
1425 class ScanlineGen2,
1426 class Scanline1,
1427 class Scanline2,
1428 class Scanline,
1429 class Renderer>
1430 void sbool_xor_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1431 Scanline1& sl1, Scanline2& sl2,
1432 Scanline& sl, Renderer& ren)
1434 sbool_add_span_bin<Scanline1, Scanline> add_functor1;
1435 sbool_add_span_bin<Scanline2, Scanline> add_functor2;
1436 sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
1437 sbool_unite_shapes(sg1, sg2, sl1, sl2, sl, ren,
1438 add_functor1, add_functor2, combine_functor);
1446 //----------------------------------------------sbool_subtract_shapes_aa
1447 // Subtract shapes "sg1-sg2" with anti-aliasing
1448 // See intersect_shapes_aa for more comments
1449 //----------
1450 template<class ScanlineGen1,
1451 class ScanlineGen2,
1452 class Scanline1,
1453 class Scanline2,
1454 class Scanline,
1455 class Renderer>
1456 void sbool_subtract_shapes_aa(ScanlineGen1& sg1, ScanlineGen2& sg2,
1457 Scanline1& sl1, Scanline2& sl2,
1458 Scanline& sl, Renderer& ren)
1460 sbool_add_span_aa<Scanline1, Scanline> add_functor;
1461 sbool_subtract_spans_aa<Scanline1, Scanline2, Scanline> combine_functor;
1462 sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
1463 add_functor, combine_functor);
1470 //---------------------------------------------sbool_subtract_shapes_bin
1471 // Subtract binary shapes "sg1-sg2" without anti-aliasing
1472 // See intersect_shapes_aa for more comments
1473 //----------
1474 template<class ScanlineGen1,
1475 class ScanlineGen2,
1476 class Scanline1,
1477 class Scanline2,
1478 class Scanline,
1479 class Renderer>
1480 void sbool_subtract_shapes_bin(ScanlineGen1& sg1, ScanlineGen2& sg2,
1481 Scanline1& sl1, Scanline2& sl2,
1482 Scanline& sl, Renderer& ren)
1484 sbool_add_span_bin<Scanline1, Scanline> add_functor;
1485 sbool_combine_spans_empty<Scanline1, Scanline2, Scanline> combine_functor;
1486 sbool_subtract_shapes(sg1, sg2, sl1, sl2, sl, ren,
1487 add_functor, combine_functor);
1495 //------------------------------------------------------------sbool_op_e
1496 enum sbool_op_e
1498 sbool_or, //----sbool_or
1499 sbool_and, //----sbool_and
1500 sbool_xor, //----sbool_xor
1501 sbool_xor_saddle, //----sbool_xor_saddle
1502 sbool_xor_abs_diff, //----sbool_xor_abs_diff
1503 sbool_a_minus_b, //----sbool_a_minus_b
1504 sbool_b_minus_a //----sbool_b_minus_a
1512 //----------------------------------------------sbool_combine_shapes_bin
1513 template<class ScanlineGen1,
1514 class ScanlineGen2,
1515 class Scanline1,
1516 class Scanline2,
1517 class Scanline,
1518 class Renderer>
1519 void sbool_combine_shapes_bin(sbool_op_e op,
1520 ScanlineGen1& sg1, ScanlineGen2& sg2,
1521 Scanline1& sl1, Scanline2& sl2,
1522 Scanline& sl, Renderer& ren)
1524 switch(op)
1526 case sbool_or : sbool_unite_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
1527 case sbool_and : sbool_intersect_shapes_bin(sg1, sg2, sl1, sl2, sl, ren); break;
1528 case sbool_xor :
1529 case sbool_xor_saddle :
1530 case sbool_xor_abs_diff: sbool_xor_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
1531 case sbool_a_minus_b : sbool_subtract_shapes_bin (sg1, sg2, sl1, sl2, sl, ren); break;
1532 case sbool_b_minus_a : sbool_subtract_shapes_bin (sg2, sg1, sl2, sl1, sl, ren); break;
1539 //-----------------------------------------------sbool_combine_shapes_aa
1540 template<class ScanlineGen1,
1541 class ScanlineGen2,
1542 class Scanline1,
1543 class Scanline2,
1544 class Scanline,
1545 class Renderer>
1546 void sbool_combine_shapes_aa(sbool_op_e op,
1547 ScanlineGen1& sg1, ScanlineGen2& sg2,
1548 Scanline1& sl1, Scanline2& sl2,
1549 Scanline& sl, Renderer& ren)
1551 switch(op)
1553 case sbool_or : sbool_unite_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
1554 case sbool_and : sbool_intersect_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
1555 case sbool_xor : sbool_xor_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
1556 case sbool_xor_saddle : sbool_xor_shapes_saddle_aa (sg1, sg2, sl1, sl2, sl, ren); break;
1557 case sbool_xor_abs_diff: sbool_xor_shapes_abs_diff_aa(sg1, sg2, sl1, sl2, sl, ren); break;
1558 case sbool_a_minus_b : sbool_subtract_shapes_aa (sg1, sg2, sl1, sl2, sl, ren); break;
1559 case sbool_b_minus_a : sbool_subtract_shapes_aa (sg2, sg1, sl2, sl1, sl, ren); break;
1566 #endif