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 //----------------------------------------------------------------------------
15 #ifndef AGG_RENDERER_OUTLINE_IMAGE_INCLUDED
16 #define AGG_RENDERER_OUTLINE_IMAGE_INCLUDED
17 
18 #include <cstdlib>
19 #include "agg_array.h"
20 #include "agg_math.h"
21 #include "agg_line_aa_basics.h"
22 #include "agg_dda_line.h"
23 #include "agg_rendering_buffer.h"
24 #include "agg_clip_liang_barsky.h"
25 
26 
27 namespace agg
28 {
29     //========================================================line_image_scale
30     template<class Source> class line_image_scale
31     {
32     public:
33         typedef typename Source::color_type color_type;
34 
line_image_scale(const Source & src,double height)35         line_image_scale(const Source& src, double height) :
36             m_source(src),
37             m_height(height),
38             m_scale(src.height() / height),
39             m_scale_inv(height / src.height())
40         {
41         }
42 
width()43         double width()  const { return m_source.width(); }
height()44         double height() const { return m_height; }
45 
pixel(int x,int y)46         color_type pixel(int x, int y) const
47         {
48             if (m_scale < 1.0)
49             {
50                 // Interpolate between nearest source pixels.
51                 double src_y = (y + 0.5) * m_scale - 0.5;
52                 int h  = m_source.height() - 1;
53                 int y1 = ifloor(src_y);
54                 int y2 = y1 + 1;
55                 rgba pix1 = (y1 < 0) ? rgba::no_color() : rgba(m_source.pixel(x, y1));
56                 rgba pix2 = (y2 > h) ? rgba::no_color() : rgba(m_source.pixel(x, y2));
57                 return pix1.gradient(pix2, src_y - y1);
58             }
59             else
60             {
61                 // Average source pixels between y and y+1.
62                 double src_y1 = (y + 0.5) * m_scale - 0.5;
63                 double src_y2 = src_y1 + m_scale;
64                 int h  = m_source.height() - 1;
65                 int y1 = ifloor(src_y1);
66                 int y2 = ifloor(src_y2);
67                 rgba c = rgba::no_color();
68                 if (y1 >= 0) c += rgba(m_source.pixel(x, y1)) *= y1 + 1 - src_y1;
69                 while (++y1 < y2)
70                 {
71                     if (y1 <= h) c += m_source.pixel(x, y1);
72                 }
73                 if (y2 <= h) c += rgba(m_source.pixel(x, y2)) *= src_y2 - y2;
74                 return c *= m_scale_inv;
75             }
76         }
77 
78     private:
79         line_image_scale(const line_image_scale<Source>&);
80         const line_image_scale<Source>& operator = (const line_image_scale<Source>&);
81 
82         const Source& m_source;
83         double        m_height;
84         double        m_scale;
85         double        m_scale_inv;
86     };
87 
88 
89 
90     //======================================================line_image_pattern
91     template<class Filter> class line_image_pattern
92     {
93     public:
94         typedef Filter filter_type;
95         typedef typename filter_type::color_type color_type;
96 
97         //--------------------------------------------------------------------
line_image_pattern(Filter & filter)98         line_image_pattern(Filter& filter) :
99             m_filter(&filter),
100             m_dilation(filter.dilation() + 1),
101             m_dilation_hr(m_dilation << line_subpixel_shift),
102             m_data(),
103             m_width(0),
104             m_height(0),
105             m_width_hr(0),
106             m_half_height_hr(0),
107             m_offset_y_hr(0)
108         {
109         }
110 
111         // Create
112         //--------------------------------------------------------------------
113         template<class Source>
line_image_pattern(Filter & filter,const Source & src)114         line_image_pattern(Filter& filter, const Source& src) :
115             m_filter(&filter),
116             m_dilation(filter.dilation() + 1),
117             m_dilation_hr(m_dilation << line_subpixel_shift),
118             m_data(),
119             m_width(0),
120             m_height(0),
121             m_width_hr(0),
122             m_half_height_hr(0),
123             m_offset_y_hr(0)
124         {
125             create(src);
126         }
127 
128         // Create
129         //--------------------------------------------------------------------
create(const Source & src)130         template<class Source> void create(const Source& src)
131         {
132             m_height = uceil(src.height());
133             m_width  = uceil(src.width());
134             m_width_hr = uround(src.width() * line_subpixel_scale);
135             m_half_height_hr = uround(src.height() * line_subpixel_scale/2);
136             m_offset_y_hr = m_dilation_hr + m_half_height_hr - line_subpixel_scale/2;
137             m_half_height_hr += line_subpixel_scale/2;
138 
139             m_data.resize((m_width + m_dilation * 2) * (m_height + m_dilation * 2));
140 
141             m_buf.attach(&m_data[0], m_width  + m_dilation * 2,
142                                      m_height + m_dilation * 2,
143                                      m_width  + m_dilation * 2);
144             unsigned x, y;
145             color_type* d1;
146             color_type* d2;
147             for(y = 0; y < m_height; y++)
148             {
149                 d1 = m_buf.row_ptr(y + m_dilation) + m_dilation;
150                 for(x = 0; x < m_width; x++)
151                 {
152                     *d1++ = src.pixel(x, y);
153                 }
154             }
155 
156             const color_type* s1;
157             const color_type* s2;
158             for(y = 0; y < m_dilation; y++)
159             {
160                 //s1 = m_buf.row_ptr(m_height + m_dilation - 1) + m_dilation;
161                 //s2 = m_buf.row_ptr(m_dilation) + m_dilation;
162                 d1 = m_buf.row_ptr(m_dilation + m_height + y) + m_dilation;
163                 d2 = m_buf.row_ptr(m_dilation - y - 1) + m_dilation;
164                 for(x = 0; x < m_width; x++)
165                 {
166                     //*d1++ = color_type(*s1++, 0);
167                     //*d2++ = color_type(*s2++, 0);
168                     *d1++ = color_type::no_color();
169                     *d2++ = color_type::no_color();
170                 }
171             }
172 
173             unsigned h = m_height + m_dilation * 2;
174             for(y = 0; y < h; y++)
175             {
176                 s1 = m_buf.row_ptr(y) + m_dilation;
177                 s2 = m_buf.row_ptr(y) + m_dilation + m_width;
178                 d1 = m_buf.row_ptr(y) + m_dilation + m_width;
179                 d2 = m_buf.row_ptr(y) + m_dilation;
180 
181                 for(x = 0; x < m_dilation; x++)
182                 {
183                     *d1++ = *s1++;
184                     *--d2 = *--s2;
185                 }
186             }
187         }
188 
189         //--------------------------------------------------------------------
pattern_width()190         int pattern_width() const { return m_width_hr; }
line_width()191         int line_width()    const { return m_half_height_hr; }
width()192         double width()      const { return m_height; }
193 
194         //--------------------------------------------------------------------
pixel(color_type * p,int x,int y)195         void pixel(color_type* p, int x, int y) const
196         {
197             m_filter->pixel_high_res(m_buf.rows(),
198                                      p,
199                                      x % m_width_hr + m_dilation_hr,
200                                      y + m_offset_y_hr);
201         }
202 
203         //--------------------------------------------------------------------
filter()204         const filter_type& filter() const { return *m_filter; }
205 
206     private:
207         line_image_pattern(const line_image_pattern<filter_type>&);
208         const line_image_pattern<filter_type>&
209             operator = (const line_image_pattern<filter_type>&);
210 
211     protected:
212         row_ptr_cache<color_type> m_buf;
213         const filter_type*        m_filter;
214         unsigned                  m_dilation;
215         int                       m_dilation_hr;
216         pod_array<color_type>     m_data;
217         unsigned                  m_width;
218         unsigned                  m_height;
219         int                       m_width_hr;
220         int                       m_half_height_hr;
221         int                       m_offset_y_hr;
222     };
223 
224 
225 
226 
227 
228 
229     //=================================================line_image_pattern_pow2
230     template<class Filter> class line_image_pattern_pow2 :
231     public line_image_pattern<Filter>
232     {
233     public:
234         typedef Filter filter_type;
235         typedef typename filter_type::color_type color_type;
236         typedef line_image_pattern<Filter> base_type;
237 
238         //--------------------------------------------------------------------
line_image_pattern_pow2(Filter & filter)239         line_image_pattern_pow2(Filter& filter) :
240             line_image_pattern<Filter>(filter), m_mask(line_subpixel_mask) {}
241 
242         //--------------------------------------------------------------------
243         template<class Source>
line_image_pattern_pow2(Filter & filter,const Source & src)244         line_image_pattern_pow2(Filter& filter, const Source& src) :
245             line_image_pattern<Filter>(filter), m_mask(line_subpixel_mask)
246         {
247             create(src);
248         }
249 
250         //--------------------------------------------------------------------
create(const Source & src)251         template<class Source> void create(const Source& src)
252         {
253             line_image_pattern<Filter>::create(src);
254             m_mask = 1;
255             while(m_mask < base_type::m_width)
256             {
257                 m_mask <<= 1;
258                 m_mask |= 1;
259             }
260             m_mask <<= line_subpixel_shift - 1;
261             m_mask |=  line_subpixel_mask;
262             base_type::m_width_hr = m_mask + 1;
263         }
264 
265         //--------------------------------------------------------------------
pixel(color_type * p,int x,int y)266         void pixel(color_type* p, int x, int y) const
267         {
268             base_type::m_filter->pixel_high_res(
269                     base_type::m_buf.rows(),
270                     p,
271                     (x & m_mask) + base_type::m_dilation_hr,
272                     y + base_type::m_offset_y_hr);
273         }
274     private:
275         unsigned m_mask;
276     };
277 
278 
279 
280 
281 
282 
283 
284     //===================================================distance_interpolator4
285     class distance_interpolator4
286     {
287     public:
288         //---------------------------------------------------------------------
distance_interpolator4()289         distance_interpolator4() {}
distance_interpolator4(int x1,int y1,int x2,int y2,int sx,int sy,int ex,int ey,int len,double scale,int x,int y)290         distance_interpolator4(int x1,  int y1, int x2, int y2,
291                                int sx,  int sy, int ex, int ey,
292                                int len, double scale, int x, int y) :
293             m_dx(x2 - x1),
294             m_dy(y2 - y1),
295             m_dx_start(line_mr(sx) - line_mr(x1)),
296             m_dy_start(line_mr(sy) - line_mr(y1)),
297             m_dx_end(line_mr(ex) - line_mr(x2)),
298             m_dy_end(line_mr(ey) - line_mr(y2)),
299 
300             m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) -
301                           double(y + line_subpixel_scale/2 - y2) * double(m_dx))),
302 
303             m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start -
304                          (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start),
305 
306             m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end -
307                        (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end),
308             m_len(uround(len / scale))
309         {
310             double d = len * scale;
311             int dx = iround(((x2 - x1) << line_subpixel_shift) / d);
312             int dy = iround(((y2 - y1) << line_subpixel_shift) / d);
313             m_dx_pict   = -dy;
314             m_dy_pict   =  dx;
315             m_dist_pict =  ((x + line_subpixel_scale/2 - (x1 - dy)) * m_dy_pict -
316                             (y + line_subpixel_scale/2 - (y1 + dx)) * m_dx_pict) >>
317                            line_subpixel_shift;
318 
319             m_dx       <<= line_subpixel_shift;
320             m_dy       <<= line_subpixel_shift;
321             m_dx_start <<= line_mr_subpixel_shift;
322             m_dy_start <<= line_mr_subpixel_shift;
323             m_dx_end   <<= line_mr_subpixel_shift;
324             m_dy_end   <<= line_mr_subpixel_shift;
325         }
326 
327         //---------------------------------------------------------------------
inc_x()328         void inc_x()
329         {
330             m_dist += m_dy;
331             m_dist_start += m_dy_start;
332             m_dist_pict += m_dy_pict;
333             m_dist_end += m_dy_end;
334         }
335 
336         //---------------------------------------------------------------------
dec_x()337         void dec_x()
338         {
339             m_dist -= m_dy;
340             m_dist_start -= m_dy_start;
341             m_dist_pict -= m_dy_pict;
342             m_dist_end -= m_dy_end;
343         }
344 
345         //---------------------------------------------------------------------
inc_y()346         void inc_y()
347         {
348             m_dist -= m_dx;
349             m_dist_start -= m_dx_start;
350             m_dist_pict -= m_dx_pict;
351             m_dist_end -= m_dx_end;
352         }
353 
354         //---------------------------------------------------------------------
dec_y()355         void dec_y()
356         {
357             m_dist += m_dx;
358             m_dist_start += m_dx_start;
359             m_dist_pict += m_dx_pict;
360             m_dist_end += m_dx_end;
361         }
362 
363         //---------------------------------------------------------------------
inc_x(int dy)364         void inc_x(int dy)
365         {
366             m_dist       += m_dy;
367             m_dist_start += m_dy_start;
368             m_dist_pict  += m_dy_pict;
369             m_dist_end   += m_dy_end;
370             if(dy > 0)
371             {
372                 m_dist       -= m_dx;
373                 m_dist_start -= m_dx_start;
374                 m_dist_pict  -= m_dx_pict;
375                 m_dist_end   -= m_dx_end;
376             }
377             if(dy < 0)
378             {
379                 m_dist       += m_dx;
380                 m_dist_start += m_dx_start;
381                 m_dist_pict  += m_dx_pict;
382                 m_dist_end   += m_dx_end;
383             }
384         }
385 
386         //---------------------------------------------------------------------
dec_x(int dy)387         void dec_x(int dy)
388         {
389             m_dist       -= m_dy;
390             m_dist_start -= m_dy_start;
391             m_dist_pict  -= m_dy_pict;
392             m_dist_end   -= m_dy_end;
393             if(dy > 0)
394             {
395                 m_dist       -= m_dx;
396                 m_dist_start -= m_dx_start;
397                 m_dist_pict  -= m_dx_pict;
398                 m_dist_end   -= m_dx_end;
399             }
400             if(dy < 0)
401             {
402                 m_dist       += m_dx;
403                 m_dist_start += m_dx_start;
404                 m_dist_pict  += m_dx_pict;
405                 m_dist_end   += m_dx_end;
406             }
407         }
408 
409         //---------------------------------------------------------------------
inc_y(int dx)410         void inc_y(int dx)
411         {
412             m_dist       -= m_dx;
413             m_dist_start -= m_dx_start;
414             m_dist_pict  -= m_dx_pict;
415             m_dist_end   -= m_dx_end;
416             if(dx > 0)
417             {
418                 m_dist       += m_dy;
419                 m_dist_start += m_dy_start;
420                 m_dist_pict  += m_dy_pict;
421                 m_dist_end   += m_dy_end;
422             }
423             if(dx < 0)
424             {
425                 m_dist       -= m_dy;
426                 m_dist_start -= m_dy_start;
427                 m_dist_pict  -= m_dy_pict;
428                 m_dist_end   -= m_dy_end;
429             }
430         }
431 
432         //---------------------------------------------------------------------
dec_y(int dx)433         void dec_y(int dx)
434         {
435             m_dist       += m_dx;
436             m_dist_start += m_dx_start;
437             m_dist_pict  += m_dx_pict;
438             m_dist_end   += m_dx_end;
439             if(dx > 0)
440             {
441                 m_dist       += m_dy;
442                 m_dist_start += m_dy_start;
443                 m_dist_pict  += m_dy_pict;
444                 m_dist_end   += m_dy_end;
445             }
446             if(dx < 0)
447             {
448                 m_dist       -= m_dy;
449                 m_dist_start -= m_dy_start;
450                 m_dist_pict  -= m_dy_pict;
451                 m_dist_end   -= m_dy_end;
452             }
453         }
454 
455         //---------------------------------------------------------------------
dist()456         int dist()       const { return m_dist;       }
dist_start()457         int dist_start() const { return m_dist_start; }
dist_pict()458         int dist_pict()  const { return m_dist_pict;  }
dist_end()459         int dist_end()   const { return m_dist_end;   }
460 
461         //---------------------------------------------------------------------
dx()462         int dx()       const { return m_dx;       }
dy()463         int dy()       const { return m_dy;       }
dx_start()464         int dx_start() const { return m_dx_start; }
dy_start()465         int dy_start() const { return m_dy_start; }
dx_pict()466         int dx_pict()  const { return m_dx_pict;  }
dy_pict()467         int dy_pict()  const { return m_dy_pict;  }
dx_end()468         int dx_end()   const { return m_dx_end;   }
dy_end()469         int dy_end()   const { return m_dy_end;   }
len()470         int len()      const { return m_len;      }
471 
472     private:
473         //---------------------------------------------------------------------
474         int m_dx;
475         int m_dy;
476         int m_dx_start;
477         int m_dy_start;
478         int m_dx_pict;
479         int m_dy_pict;
480         int m_dx_end;
481         int m_dy_end;
482 
483         int m_dist;
484         int m_dist_start;
485         int m_dist_pict;
486         int m_dist_end;
487         int m_len;
488     };
489 
490 
491 
492 
493 
494     //==================================================line_interpolator_image
495     template<class Renderer> class line_interpolator_image
496     {
497     public:
498         typedef Renderer renderer_type;
499         typedef typename Renderer::color_type color_type;
500 
501         //---------------------------------------------------------------------
502         enum max_half_width_e
503         {
504             max_half_width = 64
505         };
506 
507         //---------------------------------------------------------------------
line_interpolator_image(renderer_type & ren,const line_parameters & lp,int sx,int sy,int ex,int ey,int pattern_start,double scale_x)508         line_interpolator_image(renderer_type& ren, const line_parameters& lp,
509                                 int sx, int sy, int ex, int ey,
510                                 int pattern_start,
511                                 double scale_x) :
512             m_lp(lp),
513             m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) :
514                                line_dbl_hr(lp.y2 - lp.y1),
515                  lp.vertical ? std::abs(lp.y2 - lp.y1) :
516                                std::abs(lp.x2 - lp.x1) + 1),
517             m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, lp.len, scale_x,
518                  lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask),
519             m_ren(ren),
520             m_x(lp.x1 >> line_subpixel_shift),
521             m_y(lp.y1 >> line_subpixel_shift),
522             m_old_x(m_x),
523             m_old_y(m_y),
524             m_count((lp.vertical ? std::abs((lp.y2 >> line_subpixel_shift) - m_y) :
525                                    std::abs((lp.x2 >> line_subpixel_shift) - m_x))),
526             m_width(ren.subpixel_width()),
527             //m_max_extent(m_width >> (line_subpixel_shift - 2)),
528             m_max_extent((m_width + line_subpixel_scale) >> line_subpixel_shift),
529             m_start(pattern_start + (m_max_extent + 2) * ren.pattern_width()),
530             m_step(0)
531         {
532             agg::dda2_line_interpolator li(0, lp.vertical ?
533                                               (lp.dy << agg::line_subpixel_shift) :
534                                               (lp.dx << agg::line_subpixel_shift),
535                                            lp.len);
536 
537             unsigned i;
538             int stop = m_width + line_subpixel_scale * 2;
539             for(i = 0; i < max_half_width; ++i)
540             {
541                 m_dist_pos[i] = li.y();
542                 if(m_dist_pos[i] >= stop) break;
543                 ++li;
544             }
545             m_dist_pos[i] = 0x7FFF0000;
546 
547             int dist1_start;
548             int dist2_start;
549             int npix = 1;
550 
551             if(lp.vertical)
552             {
553                 do
554                 {
555                     --m_li;
556                     m_y -= lp.inc;
557                     m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift;
558 
559                     if(lp.inc > 0) m_di.dec_y(m_x - m_old_x);
560                     else           m_di.inc_y(m_x - m_old_x);
561 
562                     m_old_x = m_x;
563 
564                     dist1_start = dist2_start = m_di.dist_start();
565 
566                     int dx = 0;
567                     if(dist1_start < 0) ++npix;
568                     do
569                     {
570                         dist1_start += m_di.dy_start();
571                         dist2_start -= m_di.dy_start();
572                         if(dist1_start < 0) ++npix;
573                         if(dist2_start < 0) ++npix;
574                         ++dx;
575                     }
576                     while(m_dist_pos[dx] <= m_width);
577                     if(npix == 0) break;
578 
579                     npix = 0;
580                 }
581                 while(--m_step >= -m_max_extent);
582             }
583             else
584             {
585                 do
586                 {
587                     --m_li;
588 
589                     m_x -= lp.inc;
590                     m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift;
591 
592                     if(lp.inc > 0) m_di.dec_x(m_y - m_old_y);
593                     else           m_di.inc_x(m_y - m_old_y);
594 
595                     m_old_y = m_y;
596 
597                     dist1_start = dist2_start = m_di.dist_start();
598 
599                     int dy = 0;
600                     if(dist1_start < 0) ++npix;
601                     do
602                     {
603                         dist1_start -= m_di.dx_start();
604                         dist2_start += m_di.dx_start();
605                         if(dist1_start < 0) ++npix;
606                         if(dist2_start < 0) ++npix;
607                         ++dy;
608                     }
609                     while(m_dist_pos[dy] <= m_width);
610                     if(npix == 0) break;
611 
612                     npix = 0;
613                 }
614                 while(--m_step >= -m_max_extent);
615             }
616             m_li.adjust_forward();
617             m_step -= m_max_extent;
618         }
619 
620         //---------------------------------------------------------------------
step_hor()621         bool step_hor()
622         {
623             ++m_li;
624             m_x += m_lp.inc;
625             m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift;
626 
627             if(m_lp.inc > 0) m_di.inc_x(m_y - m_old_y);
628             else             m_di.dec_x(m_y - m_old_y);
629 
630             m_old_y = m_y;
631 
632             int s1 = m_di.dist() / m_lp.len;
633             int s2 = -s1;
634 
635             if(m_lp.inc < 0) s1 = -s1;
636 
637             int dist_start;
638             int dist_pict;
639             int dist_end;
640             int dy;
641             int dist;
642 
643             dist_start = m_di.dist_start();
644             dist_pict  = m_di.dist_pict() + m_start;
645             dist_end   = m_di.dist_end();
646             color_type* p0 = m_colors + max_half_width + 2;
647             color_type* p1 = p0;
648 
649             int npix = 0;
650             p1->clear();
651             if(dist_end > 0)
652             {
653                 if(dist_start <= 0)
654                 {
655                     m_ren.pixel(p1, dist_pict, s2);
656                 }
657                 ++npix;
658             }
659             ++p1;
660 
661             dy = 1;
662             while((dist = m_dist_pos[dy]) - s1 <= m_width)
663             {
664                 dist_start -= m_di.dx_start();
665                 dist_pict  -= m_di.dx_pict();
666                 dist_end   -= m_di.dx_end();
667                 p1->clear();
668                 if(dist_end > 0 && dist_start <= 0)
669                 {
670                     if(m_lp.inc > 0) dist = -dist;
671                     m_ren.pixel(p1, dist_pict, s2 - dist);
672                     ++npix;
673                 }
674                 ++p1;
675                 ++dy;
676             }
677 
678             dy = 1;
679             dist_start = m_di.dist_start();
680             dist_pict  = m_di.dist_pict() + m_start;
681             dist_end   = m_di.dist_end();
682             while((dist = m_dist_pos[dy]) + s1 <= m_width)
683             {
684                 dist_start += m_di.dx_start();
685                 dist_pict  += m_di.dx_pict();
686                 dist_end   += m_di.dx_end();
687                 --p0;
688                 p0->clear();
689                 if(dist_end > 0 && dist_start <= 0)
690                 {
691                     if(m_lp.inc > 0) dist = -dist;
692                     m_ren.pixel(p0, dist_pict, s2 + dist);
693                     ++npix;
694                 }
695                 ++dy;
696             }
697             m_ren.blend_color_vspan(m_x,
698                                     m_y - dy + 1,
699                                     unsigned(p1 - p0),
700                                     p0);
701             return npix && ++m_step < m_count;
702         }
703 
704 
705 
706         //---------------------------------------------------------------------
step_ver()707         bool step_ver()
708         {
709             ++m_li;
710             m_y += m_lp.inc;
711             m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift;
712 
713             if(m_lp.inc > 0) m_di.inc_y(m_x - m_old_x);
714             else             m_di.dec_y(m_x - m_old_x);
715 
716             m_old_x = m_x;
717 
718             int s1 = m_di.dist() / m_lp.len;
719             int s2 = -s1;
720 
721             if(m_lp.inc > 0) s1 = -s1;
722 
723             int dist_start;
724             int dist_pict;
725             int dist_end;
726             int dist;
727             int dx;
728 
729             dist_start = m_di.dist_start();
730             dist_pict  = m_di.dist_pict() + m_start;
731             dist_end   = m_di.dist_end();
732             color_type* p0 = m_colors + max_half_width + 2;
733             color_type* p1 = p0;
734 
735             int npix = 0;
736             p1->clear();
737             if(dist_end > 0)
738             {
739                 if(dist_start <= 0)
740                 {
741                     m_ren.pixel(p1, dist_pict, s2);
742                 }
743                 ++npix;
744             }
745             ++p1;
746 
747             dx = 1;
748             while((dist = m_dist_pos[dx]) - s1 <= m_width)
749             {
750                 dist_start += m_di.dy_start();
751                 dist_pict  += m_di.dy_pict();
752                 dist_end   += m_di.dy_end();
753                 p1->clear();
754                 if(dist_end > 0 && dist_start <= 0)
755                 {
756                     if(m_lp.inc > 0) dist = -dist;
757                     m_ren.pixel(p1, dist_pict, s2 + dist);
758                     ++npix;
759                 }
760                 ++p1;
761                 ++dx;
762             }
763 
764             dx = 1;
765             dist_start = m_di.dist_start();
766             dist_pict  = m_di.dist_pict() + m_start;
767             dist_end   = m_di.dist_end();
768             while((dist = m_dist_pos[dx]) + s1 <= m_width)
769             {
770                 dist_start -= m_di.dy_start();
771                 dist_pict  -= m_di.dy_pict();
772                 dist_end   -= m_di.dy_end();
773                 --p0;
774                 p0->clear();
775                 if(dist_end > 0 && dist_start <= 0)
776                 {
777                     if(m_lp.inc > 0) dist = -dist;
778                     m_ren.pixel(p0, dist_pict, s2 - dist);
779                     ++npix;
780                 }
781                 ++dx;
782             }
783             m_ren.blend_color_hspan(m_x - dx + 1,
784                                     m_y,
785                                     unsigned(p1 - p0),
786                                     p0);
787             return npix && ++m_step < m_count;
788         }
789 
790 
791         //---------------------------------------------------------------------
pattern_end()792         int  pattern_end() const { return m_start + m_di.len(); }
793 
794         //---------------------------------------------------------------------
vertical()795         bool vertical() const { return m_lp.vertical; }
width()796         int  width() const { return m_width; }
count()797         int  count() const { return m_count; }
798 
799     private:
800         line_interpolator_image(const line_interpolator_image<Renderer>&);
801         const line_interpolator_image<Renderer>&
802             operator = (const line_interpolator_image<Renderer>&);
803 
804     protected:
805         const line_parameters& m_lp;
806         dda2_line_interpolator m_li;
807         distance_interpolator4 m_di;
808         renderer_type&         m_ren;
809         int m_plen;
810         int m_x;
811         int m_y;
812         int m_old_x;
813         int m_old_y;
814         int m_count;
815         int m_width;
816         int m_max_extent;
817         int m_start;
818         int m_step;
819         int m_dist_pos[max_half_width + 1];
820         color_type m_colors[max_half_width * 2 + 4];
821     };
822 
823 
824 
825 
826 
827 
828 
829 
830     //===================================================renderer_outline_image
831     template<class BaseRenderer, class ImagePattern>
832     class renderer_outline_image
833     {
834     public:
835         //---------------------------------------------------------------------
836         typedef BaseRenderer base_ren_type;
837         typedef renderer_outline_image<BaseRenderer, ImagePattern> self_type;
838         typedef typename base_ren_type::color_type color_type;
839         typedef ImagePattern pattern_type;
840 
841 
842         //---------------------------------------------------------------------
renderer_outline_image(base_ren_type & ren,pattern_type & patt)843         renderer_outline_image(base_ren_type& ren, pattern_type& patt) :
844             m_ren(&ren),
845             m_pattern(&patt),
846             m_start(0),
847             m_scale_x(1.0),
848             m_clip_box(0,0,0,0),
849             m_clipping(false)
850         {}
attach(base_ren_type & ren)851         void attach(base_ren_type& ren) { m_ren = &ren; }
852 
853         //---------------------------------------------------------------------
pattern(pattern_type & p)854         void pattern(pattern_type& p) { m_pattern = &p; }
pattern()855         pattern_type& pattern() const { return *m_pattern; }
856 
857         //---------------------------------------------------------------------
reset_clipping()858         void reset_clipping() { m_clipping = false; }
clip_box(double x1,double y1,double x2,double y2)859         void clip_box(double x1, double y1, double x2, double y2)
860         {
861             m_clip_box.x1 = line_coord_sat::conv(x1);
862             m_clip_box.y1 = line_coord_sat::conv(y1);
863             m_clip_box.x2 = line_coord_sat::conv(x2);
864             m_clip_box.y2 = line_coord_sat::conv(y2);
865             m_clipping = true;
866         }
867 
868         //---------------------------------------------------------------------
scale_x(double s)869         void   scale_x(double s) { m_scale_x = s; }
scale_x()870         double scale_x() const   { return m_scale_x; }
871 
872         //---------------------------------------------------------------------
start_x(double s)873         void   start_x(double s) { m_start = iround(s * line_subpixel_scale); }
start_x()874         double start_x() const   { return double(m_start) / line_subpixel_scale; }
875 
876         //---------------------------------------------------------------------
subpixel_width()877         int subpixel_width() const { return m_pattern->line_width(); }
pattern_width()878         int pattern_width() const { return m_pattern->pattern_width(); }
width()879         double width() const { return double(subpixel_width()) / line_subpixel_scale; }
880 
881         //-------------------------------------------------------------------------
pixel(color_type * p,int x,int y)882         void pixel(color_type* p, int x, int y) const
883         {
884             m_pattern->pixel(p, x, y);
885         }
886 
887         //-------------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors)888         void blend_color_hspan(int x, int y, unsigned len, const color_type* colors)
889         {
890             m_ren->blend_color_hspan(x, y, len, colors, 0);
891         }
892 
893         //-------------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors)894         void blend_color_vspan(int x, int y, unsigned len, const color_type* colors)
895         {
896             m_ren->blend_color_vspan(x, y, len, colors, 0);
897         }
898 
899         //-------------------------------------------------------------------------
accurate_join_only()900         static bool accurate_join_only() { return true; }
901 
902         //-------------------------------------------------------------------------
903         template<class Cmp>
semidot(Cmp,int,int,int,int)904         void semidot(Cmp, int, int, int, int)
905         {
906         }
907 
908         //-------------------------------------------------------------------------
pie(int,int,int,int,int,int)909         void pie(int, int, int, int, int, int)
910         {
911         }
912 
913         //-------------------------------------------------------------------------
line0(const line_parameters &)914         void line0(const line_parameters&)
915         {
916         }
917 
918         //-------------------------------------------------------------------------
line1(const line_parameters &,int,int)919         void line1(const line_parameters&, int, int)
920         {
921         }
922 
923         //-------------------------------------------------------------------------
line2(const line_parameters &,int,int)924         void line2(const line_parameters&, int, int)
925         {
926         }
927 
928         //-------------------------------------------------------------------------
line3_no_clip(const line_parameters & lp,int sx,int sy,int ex,int ey)929         void line3_no_clip(const line_parameters& lp,
930                            int sx, int sy, int ex, int ey)
931         {
932             if(lp.len > line_max_length)
933             {
934                 line_parameters lp1, lp2;
935                 lp.divide(lp1, lp2);
936                 int mx = lp1.x2 + (lp1.y2 - lp1.y1);
937                 int my = lp1.y2 - (lp1.x2 - lp1.x1);
938                 line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my);
939                 line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1);
940                 return;
941             }
942 
943             fix_degenerate_bisectrix_start(lp, &sx, &sy);
944             fix_degenerate_bisectrix_end(lp, &ex, &ey);
945             line_interpolator_image<self_type> li(*this, lp,
946                                                   sx, sy,
947                                                   ex, ey,
948                                                   m_start, m_scale_x);
949             if(li.vertical())
950             {
951                 while(li.step_ver());
952             }
953             else
954             {
955                 while(li.step_hor());
956             }
957             m_start += uround(lp.len / m_scale_x);
958         }
959 
960         //-------------------------------------------------------------------------
line3(const line_parameters & lp,int sx,int sy,int ex,int ey)961         void line3(const line_parameters& lp,
962                    int sx, int sy, int ex, int ey)
963         {
964             if(m_clipping)
965             {
966                 int x1 = lp.x1;
967                 int y1 = lp.y1;
968                 int x2 = lp.x2;
969                 int y2 = lp.y2;
970                 unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box);
971                 int start = m_start;
972                 if((flags & 4) == 0)
973                 {
974                     if(flags)
975                     {
976                         line_parameters lp2(x1, y1, x2, y2,
977                                            uround(calc_distance(x1, y1, x2, y2)));
978                         if(flags & 1)
979                         {
980                             m_start += uround(calc_distance(lp.x1, lp.y1, x1, y1) / m_scale_x);
981                             sx = x1 + (y2 - y1);
982                             sy = y1 - (x2 - x1);
983                         }
984                         else
985                         {
986                             while(std::abs(sx - lp.x1) + std::abs(sy - lp.y1) > lp2.len)
987                             {
988                                 sx = (lp.x1 + sx) >> 1;
989                                 sy = (lp.y1 + sy) >> 1;
990                             }
991                         }
992                         if(flags & 2)
993                         {
994                             ex = x2 + (y2 - y1);
995                             ey = y2 - (x2 - x1);
996                         }
997                         else
998                         {
999                             while(std::abs(ex - lp.x2) + std::abs(ey - lp.y2) > lp2.len)
1000                             {
1001                                 ex = (lp.x2 + ex) >> 1;
1002                                 ey = (lp.y2 + ey) >> 1;
1003                             }
1004                         }
1005                         line3_no_clip(lp2, sx, sy, ex, ey);
1006                     }
1007                     else
1008                     {
1009                         line3_no_clip(lp, sx, sy, ex, ey);
1010                     }
1011                 }
1012                 m_start = start + uround(lp.len / m_scale_x);
1013             }
1014             else
1015             {
1016                 line3_no_clip(lp, sx, sy, ex, ey);
1017             }
1018         }
1019 
1020     private:
1021         base_ren_type*      m_ren;
1022         pattern_type* m_pattern;
1023         int                 m_start;
1024         double              m_scale_x;
1025         rect_i              m_clip_box;
1026         bool                m_clipping;
1027     };
1028 
1029 
1030 
1031 
1032 
1033 }
1034 
1035 
1036 
1037 #endif
1038