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