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
26namespace agg
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
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
41        double width()  const { return m_source.width(); }
42        double height() const { return m_height; }
43
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        //--------------------------------------------------------------------
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>
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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
166        int pattern_width() const { return m_width_hr; }
167        int line_width()    const { return m_half_height_hr; }
168        double width()      const { return m_height; }
169
170        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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>
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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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        //---------------------------------------------------------------------
265        distance_interpolator4() {}
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
432        int dist()       const { return m_dist;       }
433        int dist_start() const { return m_dist_start; }
434        int dist_pict()  const { return m_dist_pict;  }
435        int dist_end()   const { return m_dist_end;   }
436
437        //---------------------------------------------------------------------
438        int dx()       const { return m_dx;       }
439        int dy()       const { return m_dy;       }
440        int dx_start() const { return m_dx_start; }
441        int dy_start() const { return m_dy_start; }
442        int dx_pict()  const { return m_dx_pict;  }
443        int dy_pict()  const { return m_dy_pict;  }
444        int dx_end()   const { return m_dx_end;   }
445        int dy_end()   const { return m_dy_end;   }
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        //---------------------------------------------------------------------
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            agg::dda2_line_interpolator li(0, lp.vertical ?
509                                              (lp.dy << agg::line_subpixel_shift) :
510                                              (lp.dx << agg::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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
768        int  pattern_end() const { return m_start + m_di.len(); }
769
770        //---------------------------------------------------------------------
771        bool vertical() const { return m_lp.vertical; }
772        int  width() const { return m_width; }
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        //---------------------------------------------------------------------
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        {}
827        void attach(base_ren_type& ren) { m_ren = &ren; }
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 reset_clipping() { m_clipping = false; }
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        //---------------------------------------------------------------------
845        void   scale_x(double s) { m_scale_x = s; }
846        double scale_x() const   { return m_scale_x; }
847
848        //---------------------------------------------------------------------
849        void   start_x(double s) { m_start = iround(s * line_subpixel_scale); }
850        double start_x() const   { return double(m_start) / line_subpixel_scale; }
851
852        //---------------------------------------------------------------------
853        int subpixel_width() const { return m_pattern->line_width(); }
854        int pattern_width() const { return m_pattern->pattern_width(); }
855        double width() const { return double(subpixel_width()) / line_subpixel_scale; }
856
857        //-------------------------------------------------------------------------
858        void pixel(color_type* p, int x, int y) const
859        {
860            m_pattern->pixel(p, x, y);
861        }
862
863        //-------------------------------------------------------------------------
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        //-------------------------------------------------------------------------
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        //-------------------------------------------------------------------------
876        static bool accurate_join_only() { return true; }
877
878        //-------------------------------------------------------------------------
879        template<class Cmp>
880        void semidot(Cmp, int, int, int, int)
881        {
882        }
883
884        //-------------------------------------------------------------------------
885        void pie(int, int, int, int, int, int)
886        {
887        }
888
889        //-------------------------------------------------------------------------
890        void line0(const line_parameters&)
891        {
892        }
893
894        //-------------------------------------------------------------------------
895        void line1(const line_parameters&, int, int)
896        {
897        }
898
899        //-------------------------------------------------------------------------
900        void line2(const line_parameters&, int, int)
901        {
902        }
903
904        //-------------------------------------------------------------------------
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        //-------------------------------------------------------------------------
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