//--------------------------------------------------------------------
 public void generate(color_type *span, int x, int y, unsigned len)
 {
     base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                     y + base_type::filter_dy_dbl(), len);
     do
     {
         base_type::interpolator().coordinates(&x, &y);
         span->v = *(value_type *)
                   base_type::source().span(x >> image_subpixel_shift,
                                            y >> image_subpixel_shift,
                                            1);
         span->a = base_mask;
         ++span;
         ++base_type::interpolator();
     } while(--len);
 }
        //--------------------------------------------------------------------
        public void generate(color_type *span, int x, int y, unsigned len)
        {
            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                            y + base_type::filter_dy_dbl(), len);
            calc_type   fg;
            value_type *fg_ptr;

            do
            {
                int x_hr;
                int y_hr;

                base_type::interpolator().coordinates(&x_hr, &y_hr);

                x_hr -= base_type::filter_dx_int();
                y_hr -= base_type::filter_dy_int();

                int x_lr = x_hr >> image_subpixel_shift;
                int y_lr = y_hr >> image_subpixel_shift;

                fg = image_subpixel_scale * image_subpixel_scale / 2;

                x_hr &= image_subpixel_mask;
                y_hr &= image_subpixel_mask;

                fg_ptr = (value_type *)base_type::source().span(x_lr, y_lr, 2);
                fg    += *fg_ptr * (image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr);

                fg_ptr = (value_type *)base_type::source().next_x();
                fg    += *fg_ptr * x_hr * (image_subpixel_scale - y_hr);

                fg_ptr = (value_type *)base_type::source().next_y();
                fg    += *fg_ptr * (image_subpixel_scale - x_hr) * y_hr;

                fg_ptr = (value_type *)base_type::source().next_x();
                fg    += *fg_ptr * x_hr * y_hr;

                span->v = value_type(fg >> (image_subpixel_shift * 2));
                span->a = base_mask;
                ++span;
                ++base_type::interpolator();
            } while(--len);
        }
        //--------------------------------------------------------------------
        public void generate(color_type *span, int x, int y, unsigned len)
        {
            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                            y + base_type::filter_dy_dbl(), len);
            long_type fg;

            int diameter     = base_type::filter().diameter();
            int filter_scale = diameter << image_subpixel_shift;

            int16 *weight_array = base_type::filter().weight_array();

            do
            {
                int rx;
                int ry;
                int rx_inv = image_subpixel_scale;
                int ry_inv = image_subpixel_scale;
                base_type::interpolator().coordinates(&x, &y);
                base_type::interpolator().local_scale(&rx, &ry);
                base_type::adjust_scale(&rx, &ry);

                rx_inv = image_subpixel_scale * image_subpixel_scale / rx;
                ry_inv = image_subpixel_scale * image_subpixel_scale / ry;

                int radius_x = (diameter * rx) >> 1;
                int radius_y = (diameter * ry) >> 1;
                int len_x_lr =
                    (diameter * rx + image_subpixel_mask) >>
                    image_subpixel_shift;

                x += base_type::filter_dx_int() - radius_x;
                y += base_type::filter_dy_int() - radius_y;

                fg = image_filter_scale / 2;

                int y_lr = y >> image_subpixel_shift;
                int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
                            ry_inv) >>
                           image_subpixel_shift;
                int total_weight = 0;
                int x_lr         = x >> image_subpixel_shift;
                int x_hr         = ((image_subpixel_mask - (x & image_subpixel_mask)) *
                                    rx_inv) >>
                                   image_subpixel_shift;
                int         x_hr2  = x_hr;
                value_type *fg_ptr =
                    (value_type *)base_type::source().span(x_lr, y_lr, len_x_lr);

                for (;;)
                {
                    int weight_y = weight_array[y_hr];
                    x_hr = x_hr2;
                    for (;;)
                    {
                        int weight = (weight_y * weight_array[x_hr] +
                                      image_filter_scale / 2) >>
                                     downscale_shift;
                        fg           += *fg_ptr * weight;
                        total_weight += weight;
                        x_hr         += rx_inv;
                        if (x_hr >= filter_scale)
                        {
                            break;
                        }
                        fg_ptr = (value_type *)base_type::source().next_x();
                    }
                    y_hr += ry_inv;
                    if (y_hr >= filter_scale)
                    {
                        break;
                    }
                    fg_ptr = (value_type *)base_type::source().next_y();
                }

                fg /= total_weight;
                if (fg < 0)
                {
                    fg = 0;
                }
                if (fg > base_mask)
                {
                    fg = base_mask;
                }

                span->v = (value_type)fg;
                span->a = base_mask;

                ++span;
                ++base_type::interpolator();
            } while(--len);
        }
        //--------------------------------------------------------------------
        public void generate(color_type *span, int x, int y, unsigned len)
        {
            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                            y + base_type::filter_dy_dbl(), len);

            int         fg;
            value_type *fg_ptr;

            unsigned diameter     = base_type::filter().diameter();
            int      start        = base_type::filter().start();
            int16 *  weight_array = base_type::filter().weight_array();

            int x_count;
            int weight_y;

            do
            {
                base_type::interpolator().coordinates(&x, &y);

                x -= base_type::filter_dx_int();
                y -= base_type::filter_dy_int();

                int x_hr = x;
                int y_hr = y;

                int x_lr = x_hr >> image_subpixel_shift;
                int y_lr = y_hr >> image_subpixel_shift;

                fg = image_filter_scale / 2;

                int      x_fract = x_hr & image_subpixel_mask;
                unsigned y_count = diameter;

                y_hr   = image_subpixel_mask - (y_hr & image_subpixel_mask);
                fg_ptr = (value_type *)base_type::source().span(x_lr + start,
                                                                y_lr + start,
                                                                diameter);
                for (;;)
                {
                    x_count  = diameter;
                    weight_y = weight_array[y_hr];
                    x_hr     = image_subpixel_mask - x_fract;
                    for (;;)
                    {
                        fg += *fg_ptr *
                              ((weight_y * weight_array[x_hr] +
                                image_filter_scale / 2) >>
                               image_filter_shift);
                        if (--x_count == 0)
                        {
                            break;
                        }
                        x_hr  += image_subpixel_scale;
                        fg_ptr = (value_type *)base_type::source().next_x();
                    }

                    if (--y_count == 0)
                    {
                        break;
                    }
                    y_hr  += image_subpixel_scale;
                    fg_ptr = (value_type *)base_type::source().next_y();
                }

                fg >>= image_filter_shift;
                if (fg < 0)
                {
                    fg = 0;
                }
                if (fg > base_mask)
                {
                    fg = base_mask;
                }
                span->v = (value_type)fg;
                span->a = base_mask;

                ++span;
                ++base_type::interpolator();
            } while(--len);
        }
        //--------------------------------------------------------------------
        public void generate(color_type *span, int x, int y, unsigned len)
        {
            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                            y + base_type::filter_dy_dbl(), len);

            calc_type fg;

            value_type *fg_ptr;
            int16 *     weight_array = base_type::filter().weight_array() +
                                       ((base_type::filter().diameter() / 2 - 1) <<
                                   image_subpixel_shift);

            do
            {
                int x_hr;
                int y_hr;

                base_type::interpolator().coordinates(&x_hr, &y_hr);

                x_hr -= base_type::filter_dx_int();
                y_hr -= base_type::filter_dy_int();

                int x_lr = x_hr >> image_subpixel_shift;
                int y_lr = y_hr >> image_subpixel_shift;

                unsigned weight;
                fg = image_filter_scale / 2;

                x_hr &= image_subpixel_mask;
                y_hr &= image_subpixel_mask;

                fg_ptr = (value_type *)base_type::source().span(x_lr, y_lr, 2);
                weight = (weight_array[x_hr + image_subpixel_scale] *
                          weight_array[y_hr + image_subpixel_scale] +
                          image_filter_scale / 2) >>
                         image_filter_shift;
                fg += weight * *fg_ptr;

                fg_ptr = (value_type *)base_type::source().next_x();
                weight = (weight_array[x_hr] *
                          weight_array[y_hr + image_subpixel_scale] +
                          image_filter_scale / 2) >>
                         image_filter_shift;
                fg += weight * *fg_ptr;

                fg_ptr = (value_type *)base_type::source().next_y();
                weight = (weight_array[x_hr + image_subpixel_scale] *
                          weight_array[y_hr] +
                          image_filter_scale / 2) >>
                         image_filter_shift;
                fg += weight * *fg_ptr;

                fg_ptr = (value_type *)base_type::source().next_x();
                weight = (weight_array[x_hr] *
                          weight_array[y_hr] +
                          image_filter_scale / 2) >>
                         image_filter_shift;
                fg += weight * *fg_ptr;

                fg >>= image_filter_shift;
                if (fg > base_mask)
                {
                    fg = base_mask;
                }

                span->v = (value_type)fg;
                span->a = base_mask;
                ++span;
                ++base_type::interpolator();
            } while(--len);
        }
        //--------------------------------------------------------------------
        public void generate(color_type *span, int x, int y, unsigned len)
        {
            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
                                            y + base_type::filter_dy_dbl(), len);
            calc_type  fg;
            calc_type  src_alpha;
            value_type back_v = m_back_color.v;
            value_type back_a = m_back_color.a;

            value_type *fg_ptr;

            int maxx = base_type::source().width() - 1;
            int maxy = base_type::source().height() - 1;

            do
            {
                int x_hr;
                int y_hr;

                base_type::interpolator().coordinates(&x_hr, &y_hr);

                x_hr -= base_type::filter_dx_int();
                y_hr -= base_type::filter_dy_int();

                int x_lr = x_hr >> image_subpixel_shift;
                int y_lr = y_hr >> image_subpixel_shift;

                if (x_lr >= 0 && y_lr >= 0 &&
                    x_lr < maxx && y_lr < maxy)
                {
                    fg = image_subpixel_scale * image_subpixel_scale / 2;

                    x_hr  &= image_subpixel_mask;
                    y_hr  &= image_subpixel_mask;
                    fg_ptr = (value_type *)base_type::source().row_ptr(y_lr) + x_lr;

                    fg += *fg_ptr++ *(image_subpixel_scale - x_hr) * (image_subpixel_scale - y_hr);
                    fg += *fg_ptr++ *(image_subpixel_scale - y_hr) * x_hr;

                    ++y_lr;
                    fg_ptr = (value_type *)base_type::source().row_ptr(y_lr) + x_lr;

                    fg += *fg_ptr++ *(image_subpixel_scale - x_hr) * y_hr;
                    fg += *fg_ptr++ *x_hr * y_hr;

                    fg      >>= image_subpixel_shift * 2;
                    src_alpha = base_mask;
                }
                else
                {
                    unsigned weight;
                    if (x_lr < -1 || y_lr < -1 ||
                        x_lr > maxx || y_lr > maxy)
                    {
                        fg        = back_v;
                        src_alpha = back_a;
                    }
                    else
                    {
                        fg            =
                            src_alpha = image_subpixel_scale * image_subpixel_scale / 2;

                        x_hr &= image_subpixel_mask;
                        y_hr &= image_subpixel_mask;

                        weight = (image_subpixel_scale - x_hr) *
                                 (image_subpixel_scale - y_hr);
                        if (x_lr >= 0 && y_lr >= 0 &&
                            x_lr <= maxx && y_lr <= maxy)
                        {
                            fg += weight *
                                  *((value_type *)base_type::source().row_ptr(y_lr) + x_lr);
                            src_alpha += weight * base_mask;
                        }
                        else
                        {
                            fg        += back_v * weight;
                            src_alpha += back_a * weight;
                        }

                        x_lr++;

                        weight = x_hr * (image_subpixel_scale - y_hr);
                        if (x_lr >= 0 && y_lr >= 0 &&
                            x_lr <= maxx && y_lr <= maxy)
                        {
                            fg += weight *
                                  *((value_type *)base_type::source().row_ptr(y_lr) + x_lr);
                            src_alpha += weight * base_mask;
                        }
                        else
                        {
                            fg        += back_v * weight;
                            src_alpha += back_a * weight;
                        }

                        x_lr--;
                        y_lr++;

                        weight = (image_subpixel_scale - x_hr) * y_hr;
                        if (x_lr >= 0 && y_lr >= 0 &&
                            x_lr <= maxx && y_lr <= maxy)
                        {
                            fg += weight *
                                  *((value_type *)base_type::source().row_ptr(y_lr) + x_lr);
                            src_alpha += weight * base_mask;
                        }
                        else
                        {
                            fg        += back_v * weight;
                            src_alpha += back_a * weight;
                        }

                        x_lr++;

                        weight = x_hr * y_hr;
                        if (x_lr >= 0 && y_lr >= 0 &&
                            x_lr <= maxx && y_lr <= maxy)
                        {
                            fg += weight *
                                  *((value_type *)base_type::source().row_ptr(y_lr) + x_lr);
                            src_alpha += weight * base_mask;
                        }
                        else
                        {
                            fg        += back_v * weight;
                            src_alpha += back_a * weight;
                        }

                        fg        >>= image_subpixel_shift * 2;
                        src_alpha >>= image_subpixel_shift * 2;
                    }
                }

                span->v = (value_type)fg;
                span->a = (value_type)src_alpha;
                ++span;
                ++base_type::interpolator();
            } while(--len);
        }