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//
16// Adaptation for high precision colors has been sponsored by
17// Liberty Technology Systems, Inc., visit http://lib-sys.com
18//
19// Liberty Technology Systems, Inc. is the provider of
20// PostScript and PDF technology for software developers.
21//
22//----------------------------------------------------------------------------
23#ifndef AGG_SPAN_IMAGE_FILTER_GRAY_INCLUDED
24#define AGG_SPAN_IMAGE_FILTER_GRAY_INCLUDED
25
26#include "agg_basics.h"
27#include "agg_color_gray.h"
28#include "agg_span_image_filter.h"
29
30
31namespace agg
32{
33
34    //==============================================span_image_filter_gray_nn
35    template<class Source, class Interpolator>
36    class span_image_filter_gray_nn :
37    public span_image_filter<Source, Interpolator>
38    {
39    public:
40        typedef Source source_type;
41        typedef typename source_type::color_type color_type;
42        typedef Interpolator interpolator_type;
43        typedef span_image_filter<source_type, interpolator_type> base_type;
44        typedef typename color_type::value_type value_type;
45        typedef typename color_type::calc_type calc_type;
46        enum base_scale_e
47        {
48            base_shift = color_type::base_shift,
49            base_mask  = color_type::base_mask
50        };
51
52        //--------------------------------------------------------------------
53        span_image_filter_gray_nn() {}
54        span_image_filter_gray_nn(source_type& src,
55                                  interpolator_type& inter) :
56            base_type(src, inter, 0)
57        {}
58
59        //--------------------------------------------------------------------
60        void generate(color_type* span, int x, int y, unsigned len)
61        {
62            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
63                                            y + base_type::filter_dy_dbl(), len);
64            do
65            {
66                base_type::interpolator().coordinates(&x, &y);
67                span->v = *(const value_type*)
68                    base_type::source().span(x >> image_subpixel_shift,
69                                             y >> image_subpixel_shift,
70                                             1);
71                span->a = base_mask;
72                ++span;
73                ++base_type::interpolator();
74            } while(--len);
75        }
76    };
77
78
79
80    //=========================================span_image_filter_gray_bilinear
81    template<class Source, class Interpolator>
82    class span_image_filter_gray_bilinear :
83    public span_image_filter<Source, Interpolator>
84    {
85    public:
86        typedef Source source_type;
87        typedef typename source_type::color_type color_type;
88        typedef Interpolator interpolator_type;
89        typedef span_image_filter<source_type, interpolator_type> base_type;
90        typedef typename color_type::value_type value_type;
91        typedef typename color_type::calc_type calc_type;
92        enum base_scale_e
93        {
94            base_shift = color_type::base_shift,
95            base_mask  = color_type::base_mask
96        };
97
98        //--------------------------------------------------------------------
99        span_image_filter_gray_bilinear() {}
100        span_image_filter_gray_bilinear(source_type& src,
101                                        interpolator_type& inter) :
102            base_type(src, inter, 0)
103        {}
104
105
106        //--------------------------------------------------------------------
107        void generate(color_type* span, int x, int y, unsigned len)
108        {
109            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
110                                            y + base_type::filter_dy_dbl(), len);
111            calc_type fg;
112            const value_type *fg_ptr;
113            do
114            {
115                int x_hr;
116                int y_hr;
117
118                base_type::interpolator().coordinates(&x_hr, &y_hr);
119
120                x_hr -= base_type::filter_dx_int();
121                y_hr -= base_type::filter_dy_int();
122
123                int x_lr = x_hr >> image_subpixel_shift;
124                int y_lr = y_hr >> image_subpixel_shift;
125
126                fg = image_subpixel_scale * image_subpixel_scale / 2;
127
128                x_hr &= image_subpixel_mask;
129                y_hr &= image_subpixel_mask;
130
131                fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
132                fg    += *fg_ptr * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr);
133
134                fg_ptr = (const value_type*)base_type::source().next_x();
135                fg    += *fg_ptr * x_hr * (image_subpixel_scale - y_hr);
136
137                fg_ptr = (const value_type*)base_type::source().next_y();
138                fg    += *fg_ptr * (image_subpixel_scale - x_hr) * y_hr;
139
140                fg_ptr = (const value_type*)base_type::source().next_x();
141                fg    += *fg_ptr * x_hr * y_hr;
142
143                span->v = value_type(fg >> (image_subpixel_shift * 2));
144                span->a = base_mask;
145                ++span;
146                ++base_type::interpolator();
147
148            } while(--len);
149        }
150    };
151
152
153    //====================================span_image_filter_gray_bilinear_clip
154    template<class Source, class Interpolator>
155    class span_image_filter_gray_bilinear_clip :
156    public span_image_filter<Source, Interpolator>
157    {
158    public:
159        typedef Source source_type;
160        typedef typename source_type::color_type color_type;
161        typedef Interpolator interpolator_type;
162        typedef span_image_filter<source_type, interpolator_type> base_type;
163        typedef typename color_type::value_type value_type;
164        typedef typename color_type::calc_type calc_type;
165        enum base_scale_e
166        {
167            base_shift = color_type::base_shift,
168            base_mask  = color_type::base_mask
169        };
170
171        //--------------------------------------------------------------------
172        span_image_filter_gray_bilinear_clip() {}
173        span_image_filter_gray_bilinear_clip(source_type& src,
174                                             const color_type& back_color,
175                                             interpolator_type& inter) :
176            base_type(src, inter, 0),
177            m_back_color(back_color)
178        {}
179        const color_type& background_color() const { return m_back_color; }
180        void background_color(const color_type& v)   { m_back_color = v; }
181
182        //--------------------------------------------------------------------
183        void generate(color_type* span, int x, int y, unsigned len)
184        {
185            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
186                                            y + base_type::filter_dy_dbl(), len);
187            calc_type fg;
188            calc_type src_alpha;
189            value_type back_v = m_back_color.v;
190            value_type back_a = m_back_color.a;
191
192            const value_type *fg_ptr;
193
194            int maxx = base_type::source().width() - 1;
195            int maxy = base_type::source().height() - 1;
196
197            do
198            {
199                int x_hr;
200                int y_hr;
201
202                base_type::interpolator().coordinates(&x_hr, &y_hr);
203
204                x_hr -= base_type::filter_dx_int();
205                y_hr -= base_type::filter_dy_int();
206
207                int x_lr = x_hr >> image_subpixel_shift;
208                int y_lr = y_hr >> image_subpixel_shift;
209
210                if(x_lr >= 0    && y_lr >= 0 &&
211                   x_lr <  maxx && y_lr <  maxy)
212                {
213                    fg = image_subpixel_scale * image_subpixel_scale / 2;
214
215                    x_hr &= image_subpixel_mask;
216                    y_hr &= image_subpixel_mask;
217                    fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr;
218
219                    fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr);
220                    fg += *fg_ptr++ * (image_subpixel_scale - y_hr) * x_hr;
221
222                    ++y_lr;
223                    fg_ptr = (const value_type*)base_type::source().row_ptr(y_lr) + x_lr;
224
225                    fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * y_hr;
226                    fg += *fg_ptr++ * x_hr * y_hr;
227
228                    fg >>= image_subpixel_shift * 2;
229                    src_alpha = base_mask;
230                }
231                else
232                {
233                    unsigned weight;
234                    if(x_lr < -1   || y_lr < -1 ||
235                       x_lr > maxx || y_lr > maxy)
236                    {
237                        fg        = back_v;
238                        src_alpha = back_a;
239                    }
240                    else
241                    {
242                        fg =
243                        src_alpha = image_subpixel_scale * image_subpixel_scale / 2;
244
245                        x_hr &= image_subpixel_mask;
246                        y_hr &= image_subpixel_mask;
247
248                        weight = (image_subpixel_scale - x_hr) *
249                                 (image_subpixel_scale - y_hr);
250                        if(x_lr >= 0    && y_lr >= 0 &&
251                           x_lr <= maxx && y_lr <= maxy)
252                        {
253                            fg += weight *
254                                *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr);
255                            src_alpha += weight * base_mask;
256                        }
257                        else
258                        {
259                            fg        += back_v * weight;
260                            src_alpha += back_a * weight;
261                        }
262
263                        x_lr++;
264
265                        weight = x_hr * (image_subpixel_scale - y_hr);
266                        if(x_lr >= 0    && y_lr >= 0 &&
267                           x_lr <= maxx && y_lr <= maxy)
268                        {
269                            fg += weight *
270                                *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr);
271                            src_alpha += weight * base_mask;
272                        }
273                        else
274                        {
275                            fg        += back_v * weight;
276                            src_alpha += back_a * weight;
277                        }
278
279                        x_lr--;
280                        y_lr++;
281
282                        weight = (image_subpixel_scale - x_hr) * y_hr;
283                        if(x_lr >= 0    && y_lr >= 0 &&
284                           x_lr <= maxx && y_lr <= maxy)
285                        {
286                            fg += weight *
287                                *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr);
288                            src_alpha += weight * base_mask;
289                        }
290                        else
291                        {
292                            fg        += back_v * weight;
293                            src_alpha += back_a * weight;
294                        }
295
296                        x_lr++;
297
298                        weight = x_hr * y_hr;
299                        if(x_lr >= 0    && y_lr >= 0 &&
300                           x_lr <= maxx && y_lr <= maxy)
301                        {
302                            fg += weight *
303                                *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr);
304                            src_alpha += weight * base_mask;
305                        }
306                        else
307                        {
308                            fg        += back_v * weight;
309                            src_alpha += back_a * weight;
310                        }
311
312                        fg        >>= image_subpixel_shift * 2;
313                        src_alpha >>= image_subpixel_shift * 2;
314                    }
315                }
316
317                span->v = (value_type)fg;
318                span->a = (value_type)src_alpha;
319                ++span;
320                ++base_type::interpolator();
321
322            } while(--len);
323        }
324    private:
325        color_type m_back_color;
326    };
327
328
329
330    //==============================================span_image_filter_gray_2x2
331    template<class Source, class Interpolator>
332    class span_image_filter_gray_2x2 :
333    public span_image_filter<Source, Interpolator>
334    {
335    public:
336        typedef Source source_type;
337        typedef typename source_type::color_type color_type;
338        typedef Interpolator interpolator_type;
339        typedef span_image_filter<source_type, interpolator_type> base_type;
340        typedef typename color_type::value_type value_type;
341        typedef typename color_type::calc_type calc_type;
342        enum base_scale_e
343        {
344            base_shift = color_type::base_shift,
345            base_mask  = color_type::base_mask
346        };
347
348        //--------------------------------------------------------------------
349        span_image_filter_gray_2x2() {}
350        span_image_filter_gray_2x2(source_type& src,
351                                   interpolator_type& inter,
352                                   const image_filter_lut& filter) :
353            base_type(src, inter, &filter)
354        {}
355
356
357        //--------------------------------------------------------------------
358        void generate(color_type* span, int x, int y, unsigned len)
359        {
360            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
361                                            y + base_type::filter_dy_dbl(), len);
362
363            calc_type fg;
364
365            const value_type *fg_ptr;
366            const int16* weight_array = base_type::filter().weight_array() +
367                                        ((base_type::filter().diameter()/2 - 1) <<
368                                          image_subpixel_shift);
369            do
370            {
371                int x_hr;
372                int y_hr;
373
374                base_type::interpolator().coordinates(&x_hr, &y_hr);
375
376                x_hr -= base_type::filter_dx_int();
377                y_hr -= base_type::filter_dy_int();
378
379                int x_lr = x_hr >> image_subpixel_shift;
380                int y_lr = y_hr >> image_subpixel_shift;
381
382                unsigned weight;
383                fg = image_filter_scale / 2;
384
385                x_hr &= image_subpixel_mask;
386                y_hr &= image_subpixel_mask;
387
388                fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
389                weight = (weight_array[x_hr + image_subpixel_scale] *
390                          weight_array[y_hr + image_subpixel_scale] +
391                          image_filter_scale / 2) >>
392                          image_filter_shift;
393                fg += weight * *fg_ptr;
394
395                fg_ptr = (const value_type*)base_type::source().next_x();
396                weight = (weight_array[x_hr] *
397                          weight_array[y_hr + image_subpixel_scale] +
398                          image_filter_scale / 2) >>
399                          image_filter_shift;
400                fg += weight * *fg_ptr;
401
402                fg_ptr = (const value_type*)base_type::source().next_y();
403                weight = (weight_array[x_hr + image_subpixel_scale] *
404                          weight_array[y_hr] +
405                          image_filter_scale / 2) >>
406                          image_filter_shift;
407                fg += weight * *fg_ptr;
408
409                fg_ptr = (const value_type*)base_type::source().next_x();
410                weight = (weight_array[x_hr] *
411                          weight_array[y_hr] +
412                          image_filter_scale / 2) >>
413                          image_filter_shift;
414                fg += weight * *fg_ptr;
415
416                fg >>= image_filter_shift;
417                if(fg > base_mask) fg = base_mask;
418
419                span->v = (value_type)fg;
420                span->a = base_mask;
421                ++span;
422                ++base_type::interpolator();
423            } while(--len);
424        }
425    };
426
427
428
429    //==================================================span_image_filter_gray
430    template<class Source, class Interpolator>
431    class span_image_filter_gray :
432    public span_image_filter<Source, Interpolator>
433    {
434    public:
435        typedef Source source_type;
436        typedef typename source_type::color_type color_type;
437        typedef Interpolator interpolator_type;
438        typedef span_image_filter<source_type, interpolator_type> base_type;
439        typedef typename color_type::value_type value_type;
440        typedef typename color_type::calc_type calc_type;
441        enum base_scale_e
442        {
443            base_shift = color_type::base_shift,
444            base_mask  = color_type::base_mask
445        };
446
447        //--------------------------------------------------------------------
448        span_image_filter_gray() {}
449        span_image_filter_gray(source_type& src,
450                               interpolator_type& inter,
451                               const image_filter_lut& filter) :
452            base_type(src, inter, &filter)
453        {}
454
455        //--------------------------------------------------------------------
456        void generate(color_type* span, int x, int y, unsigned len)
457        {
458            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
459                                            y + base_type::filter_dy_dbl(), len);
460
461            int fg;
462            const value_type *fg_ptr;
463
464            unsigned     diameter     = base_type::filter().diameter();
465            int          start        = base_type::filter().start();
466            const int16* weight_array = base_type::filter().weight_array();
467
468            int x_count;
469            int weight_y;
470
471            do
472            {
473                base_type::interpolator().coordinates(&x, &y);
474
475                x -= base_type::filter_dx_int();
476                y -= base_type::filter_dy_int();
477
478                int x_hr = x;
479                int y_hr = y;
480
481                int x_lr = x_hr >> image_subpixel_shift;
482                int y_lr = y_hr >> image_subpixel_shift;
483
484                fg = image_filter_scale / 2;
485
486                int x_fract = x_hr & image_subpixel_mask;
487                unsigned y_count = diameter;
488
489                y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask);
490                fg_ptr = (const value_type*)base_type::source().span(x_lr + start,
491                                                                     y_lr + start,
492                                                                     diameter);
493                for(;;)
494                {
495                    x_count  = diameter;
496                    weight_y = weight_array[y_hr];
497                    x_hr = image_subpixel_mask - x_fract;
498                    for(;;)
499                    {
500                        fg += *fg_ptr *
501                              ((weight_y * weight_array[x_hr] +
502                                image_filter_scale / 2) >>
503                                image_filter_shift);
504                        if(--x_count == 0) break;
505                        x_hr  += image_subpixel_scale;
506                        fg_ptr = (const value_type*)base_type::source().next_x();
507                    }
508
509                    if(--y_count == 0) break;
510                    y_hr  += image_subpixel_scale;
511                    fg_ptr = (const value_type*)base_type::source().next_y();
512                }
513
514                fg >>= image_filter_shift;
515                if(fg < 0) fg = 0;
516                if(fg > base_mask) fg = base_mask;
517                span->v = (value_type)fg;
518                span->a = base_mask;
519
520                ++span;
521                ++base_type::interpolator();
522
523            } while(--len);
524        }
525    };
526
527
528
529    //=========================================span_image_resample_gray_affine
530    template<class Source>
531    class span_image_resample_gray_affine :
532    public span_image_resample_affine<Source>
533    {
534    public:
535        typedef Source source_type;
536        typedef typename source_type::color_type color_type;
537        typedef span_image_resample_affine<source_type> base_type;
538        typedef typename base_type::interpolator_type interpolator_type;
539        typedef typename color_type::value_type value_type;
540        typedef typename color_type::long_type long_type;
541        enum base_scale_e
542        {
543            base_shift      = color_type::base_shift,
544            base_mask       = color_type::base_mask,
545            downscale_shift = image_filter_shift
546        };
547
548        //--------------------------------------------------------------------
549        span_image_resample_gray_affine() {}
550        span_image_resample_gray_affine(source_type& src,
551                                        interpolator_type& inter,
552                                        const image_filter_lut& filter) :
553            base_type(src, inter, filter)
554        {}
555
556
557        //--------------------------------------------------------------------
558        void generate(color_type* span, int x, int y, unsigned len)
559        {
560            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
561                                            y + base_type::filter_dy_dbl(), len);
562
563            long_type fg;
564
565            int diameter     = base_type::filter().diameter();
566            int filter_scale = diameter << image_subpixel_shift;
567            int radius_x     = (diameter * base_type::m_rx) >> 1;
568            int radius_y     = (diameter * base_type::m_ry) >> 1;
569            int len_x_lr     =
570                (diameter * base_type::m_rx + image_subpixel_mask) >>
571                    image_subpixel_shift;
572
573            const int16* weight_array = base_type::filter().weight_array();
574
575            do
576            {
577                base_type::interpolator().coordinates(&x, &y);
578
579                x += base_type::filter_dx_int() - radius_x;
580                y += base_type::filter_dy_int() - radius_y;
581
582                fg = image_filter_scale / 2;
583
584                int y_lr = y >> image_subpixel_shift;
585                int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
586                                base_type::m_ry_inv) >>
587                                    image_subpixel_shift;
588                int total_weight = 0;
589                int x_lr = x >> image_subpixel_shift;
590                int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
591                                base_type::m_rx_inv) >>
592                                    image_subpixel_shift;
593
594                int x_hr2 = x_hr;
595                const value_type* fg_ptr =
596                    (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
597                for(;;)
598                {
599                    int weight_y = weight_array[y_hr];
600                    x_hr = x_hr2;
601                    for(;;)
602                    {
603                        int weight = (weight_y * weight_array[x_hr] +
604                                     image_filter_scale / 2) >>
605                                     downscale_shift;
606
607                        fg += *fg_ptr * weight;
608                        total_weight += weight;
609                        x_hr  += base_type::m_rx_inv;
610                        if(x_hr >= filter_scale) break;
611                        fg_ptr = (const value_type*)base_type::source().next_x();
612                    }
613                    y_hr += base_type::m_ry_inv;
614                    if(y_hr >= filter_scale) break;
615                    fg_ptr = (const value_type*)base_type::source().next_y();
616                }
617
618                fg /= total_weight;
619                if(fg < 0) fg = 0;
620                if(fg > base_mask) fg = base_mask;
621
622                span->v = (value_type)fg;
623                span->a = base_mask;
624
625                ++span;
626                ++base_type::interpolator();
627            } while(--len);
628        }
629    };
630
631
632
633    //================================================span_image_resample_gray
634    template<class Source, class Interpolator>
635    class span_image_resample_gray :
636    public span_image_resample<Source, Interpolator>
637    {
638    public:
639        typedef Source source_type;
640        typedef typename source_type::color_type color_type;
641        typedef Interpolator interpolator_type;
642        typedef span_image_resample<source_type, interpolator_type> base_type;
643        typedef typename color_type::value_type value_type;
644        typedef typename color_type::long_type long_type;
645        enum base_scale_e
646        {
647            base_shift = color_type::base_shift,
648            base_mask  = color_type::base_mask,
649            downscale_shift = image_filter_shift
650        };
651
652        //--------------------------------------------------------------------
653        span_image_resample_gray() {}
654        span_image_resample_gray(source_type& src,
655                                 interpolator_type& inter,
656                                 const image_filter_lut& filter) :
657            base_type(src, inter, filter)
658        {}
659
660        //--------------------------------------------------------------------
661        void generate(color_type* span, int x, int y, unsigned len)
662        {
663            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
664                                            y + base_type::filter_dy_dbl(), len);
665            long_type fg;
666
667            int diameter = base_type::filter().diameter();
668            int filter_scale = diameter << image_subpixel_shift;
669
670            const int16* weight_array = base_type::filter().weight_array();
671            do
672            {
673                int rx;
674                int ry;
675                int rx_inv = image_subpixel_scale;
676                int ry_inv = image_subpixel_scale;
677                base_type::interpolator().coordinates(&x,  &y);
678                base_type::interpolator().local_scale(&rx, &ry);
679                base_type::adjust_scale(&rx, &ry);
680
681                rx_inv = image_subpixel_scale * image_subpixel_scale / rx;
682                ry_inv = image_subpixel_scale * image_subpixel_scale / ry;
683
684                int radius_x = (diameter * rx) >> 1;
685                int radius_y = (diameter * ry) >> 1;
686                int len_x_lr =
687                    (diameter * rx + image_subpixel_mask) >>
688                        image_subpixel_shift;
689
690                x += base_type::filter_dx_int() - radius_x;
691                y += base_type::filter_dy_int() - radius_y;
692
693                fg = image_filter_scale / 2;
694
695                int y_lr = y >> image_subpixel_shift;
696                int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
697                               ry_inv) >>
698                                   image_subpixel_shift;
699                int total_weight = 0;
700                int x_lr = x >> image_subpixel_shift;
701                int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
702                               rx_inv) >>
703                                   image_subpixel_shift;
704                int x_hr2 = x_hr;
705                const value_type* fg_ptr =
706                    (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
707
708                for(;;)
709                {
710                    int weight_y = weight_array[y_hr];
711                    x_hr = x_hr2;
712                    for(;;)
713                    {
714                        int weight = (weight_y * weight_array[x_hr] +
715                                     image_filter_scale / 2) >>
716                                     downscale_shift;
717                        fg += *fg_ptr * weight;
718                        total_weight += weight;
719                        x_hr  += rx_inv;
720                        if(x_hr >= filter_scale) break;
721                        fg_ptr = (const value_type*)base_type::source().next_x();
722                    }
723                    y_hr += ry_inv;
724                    if(y_hr >= filter_scale) break;
725                    fg_ptr = (const value_type*)base_type::source().next_y();
726                }
727
728                fg /= total_weight;
729                if(fg < 0) fg = 0;
730                if(fg > base_mask) fg = base_mask;
731
732                span->v = (value_type)fg;
733                span->a = base_mask;
734
735                ++span;
736                ++base_type::interpolator();
737            } while(--len);
738        }
739    };
740
741
742}
743
744
745#endif
746
747
748
749