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