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_RGB_INCLUDED
24#define AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED
25
26#include "agg_basics.h"
27#include "agg_color_rgba.h"
28#include "agg_span_image_filter.h"
29
30
31namespace agg
32{
33
34    //===============================================span_image_filter_rgb_nn
35    template<class Source, class Interpolator>
36    class span_image_filter_rgb_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 typename source_type::order_type order_type;
43        typedef Interpolator interpolator_type;
44        typedef span_image_filter<source_type, interpolator_type> base_type;
45        typedef typename color_type::value_type value_type;
46        typedef typename color_type::calc_type calc_type;
47        enum base_scale_e
48        {
49            base_shift = color_type::base_shift,
50            base_mask  = color_type::base_mask
51        };
52
53        //--------------------------------------------------------------------
54        span_image_filter_rgb_nn() {}
55        span_image_filter_rgb_nn(source_type& src,
56                                 interpolator_type& inter) :
57            base_type(src, inter, 0)
58        {}
59
60        //--------------------------------------------------------------------
61        void generate(color_type* span, int x, int y, unsigned len)
62        {
63            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
64                                            y + base_type::filter_dy_dbl(), len);
65            do
66            {
67                base_type::interpolator().coordinates(&x, &y);
68                const value_type* fg_ptr = (const value_type*)
69                    base_type::source().span(x >> image_subpixel_shift,
70                                             y >> image_subpixel_shift,
71                                             1);
72                span->r = fg_ptr[order_type::R];
73                span->g = fg_ptr[order_type::G];
74                span->b = fg_ptr[order_type::B];
75                span->a = base_mask;
76                ++span;
77                ++base_type::interpolator();
78
79            } while(--len);
80        }
81    };
82
83
84
85    //==========================================span_image_filter_rgb_bilinear
86    template<class Source, class Interpolator>
87    class span_image_filter_rgb_bilinear :
88    public span_image_filter<Source, Interpolator>
89    {
90    public:
91        typedef Source source_type;
92        typedef typename source_type::color_type color_type;
93        typedef typename source_type::order_type order_type;
94        typedef Interpolator interpolator_type;
95        typedef span_image_filter<source_type, interpolator_type> base_type;
96        typedef typename color_type::value_type value_type;
97        typedef typename color_type::calc_type calc_type;
98        enum base_scale_e
99        {
100            base_shift = color_type::base_shift,
101            base_mask  = color_type::base_mask
102        };
103
104        //--------------------------------------------------------------------
105        span_image_filter_rgb_bilinear() {}
106        span_image_filter_rgb_bilinear(source_type& src,
107                                       interpolator_type& inter) :
108            base_type(src, inter, 0)
109        {}
110
111
112        //--------------------------------------------------------------------
113        void generate(color_type* span, int x, int y, unsigned len)
114        {
115            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
116                                            y + base_type::filter_dy_dbl(), len);
117            calc_type fg[3];
118            const value_type *fg_ptr;
119            do
120            {
121                int x_hr;
122                int y_hr;
123
124                base_type::interpolator().coordinates(&x_hr, &y_hr);
125
126                x_hr -= base_type::filter_dx_int();
127                y_hr -= base_type::filter_dy_int();
128
129                int x_lr = x_hr >> image_subpixel_shift;
130                int y_lr = y_hr >> image_subpixel_shift;
131
132                unsigned weight;
133
134                fg[0] =
135                fg[1] =
136                fg[2] = image_subpixel_scale * image_subpixel_scale / 2;
137
138                x_hr &= image_subpixel_mask;
139                y_hr &= image_subpixel_mask;
140
141                fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
142                weight = (image_subpixel_scale - x_hr) *
143                         (image_subpixel_scale - y_hr);
144                fg[0] += weight * *fg_ptr++;
145                fg[1] += weight * *fg_ptr++;
146                fg[2] += weight * *fg_ptr;
147
148                fg_ptr = (const value_type*)base_type::source().next_x();
149                weight = x_hr * (image_subpixel_scale - y_hr);
150                fg[0] += weight * *fg_ptr++;
151                fg[1] += weight * *fg_ptr++;
152                fg[2] += weight * *fg_ptr;
153
154                fg_ptr = (const value_type*)base_type::source().next_y();
155                weight = (image_subpixel_scale - x_hr) * y_hr;
156                fg[0] += weight * *fg_ptr++;
157                fg[1] += weight * *fg_ptr++;
158                fg[2] += weight * *fg_ptr;
159
160                fg_ptr = (const value_type*)base_type::source().next_x();
161                weight = x_hr * y_hr;
162                fg[0] += weight * *fg_ptr++;
163                fg[1] += weight * *fg_ptr++;
164                fg[2] += weight * *fg_ptr;
165
166                span->r = value_type(fg[order_type::R] >> (image_subpixel_shift * 2));
167                span->g = value_type(fg[order_type::G] >> (image_subpixel_shift * 2));
168                span->b = value_type(fg[order_type::B] >> (image_subpixel_shift * 2));
169                span->a = base_mask;
170
171                ++span;
172                ++base_type::interpolator();
173
174            } while(--len);
175        }
176    };
177
178
179
180    //=====================================span_image_filter_rgb_bilinear_clip
181    template<class Source, class Interpolator>
182    class span_image_filter_rgb_bilinear_clip :
183    public span_image_filter<Source, Interpolator>
184    {
185    public:
186        typedef Source source_type;
187        typedef typename source_type::color_type color_type;
188        typedef typename source_type::order_type order_type;
189        typedef Interpolator interpolator_type;
190        typedef span_image_filter<source_type, interpolator_type> base_type;
191        typedef typename color_type::value_type value_type;
192        typedef typename color_type::calc_type calc_type;
193        enum base_scale_e
194        {
195            base_shift = color_type::base_shift,
196            base_mask  = color_type::base_mask
197        };
198
199        //--------------------------------------------------------------------
200        span_image_filter_rgb_bilinear_clip() {}
201        span_image_filter_rgb_bilinear_clip(source_type& src,
202                                            const color_type& back_color,
203                                            interpolator_type& inter) :
204            base_type(src, inter, 0),
205            m_back_color(back_color)
206        {}
207        const color_type& background_color() const { return m_back_color; }
208        void background_color(const color_type& v)   { m_back_color = v; }
209
210        //--------------------------------------------------------------------
211        void generate(color_type* span, int x, int y, unsigned len)
212        {
213            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
214                                            y + base_type::filter_dy_dbl(), len);
215            calc_type fg[3];
216            calc_type src_alpha;
217            value_type back_r = m_back_color.r;
218            value_type back_g = m_back_color.g;
219            value_type back_b = m_back_color.b;
220            value_type back_a = m_back_color.a;
221
222            const value_type *fg_ptr;
223
224            int maxx = base_type::source().width() - 1;
225            int maxy = base_type::source().height() - 1;
226
227            do
228            {
229                int x_hr;
230                int y_hr;
231
232                base_type::interpolator().coordinates(&x_hr, &y_hr);
233
234                x_hr -= base_type::filter_dx_int();
235                y_hr -= base_type::filter_dy_int();
236
237                int x_lr = x_hr >> image_subpixel_shift;
238                int y_lr = y_hr >> image_subpixel_shift;
239                unsigned weight;
240
241                if(x_lr >= 0    && y_lr >= 0 &&
242                   x_lr <  maxx && y_lr <  maxy)
243                {
244                    fg[0] =
245                    fg[1] =
246                    fg[2] = image_subpixel_scale * image_subpixel_scale / 2;
247
248                    x_hr &= image_subpixel_mask;
249                    y_hr &= image_subpixel_mask;
250
251                    fg_ptr = (const value_type*)
252                        base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
253
254                    weight = (image_subpixel_scale - x_hr) *
255                             (image_subpixel_scale - y_hr);
256                    fg[0] += weight * *fg_ptr++;
257                    fg[1] += weight * *fg_ptr++;
258                    fg[2] += weight * *fg_ptr++;
259
260                    weight = x_hr * (image_subpixel_scale - y_hr);
261                    fg[0] += weight * *fg_ptr++;
262                    fg[1] += weight * *fg_ptr++;
263                    fg[2] += weight * *fg_ptr++;
264
265                    ++y_lr;
266                    fg_ptr = (const value_type*)
267                        base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
268
269                    weight = (image_subpixel_scale - x_hr) * y_hr;
270                    fg[0] += weight * *fg_ptr++;
271                    fg[1] += weight * *fg_ptr++;
272                    fg[2] += weight * *fg_ptr++;
273
274                    weight = x_hr * y_hr;
275                    fg[0] += weight * *fg_ptr++;
276                    fg[1] += weight * *fg_ptr++;
277                    fg[2] += weight * *fg_ptr++;
278
279                    fg[0] >>= image_subpixel_shift * 2;
280                    fg[1] >>= image_subpixel_shift * 2;
281                    fg[2] >>= image_subpixel_shift * 2;
282                    src_alpha = base_mask;
283                }
284                else
285                {
286                    if(x_lr < -1   || y_lr < -1 ||
287                       x_lr > maxx || y_lr > maxy)
288                    {
289                        fg[order_type::R] = back_r;
290                        fg[order_type::G] = back_g;
291                        fg[order_type::B] = back_b;
292                        src_alpha         = back_a;
293                    }
294                    else
295                    {
296                        fg[0] =
297                        fg[1] =
298                        fg[2] =
299                        src_alpha = image_subpixel_scale * image_subpixel_scale / 2;
300
301                        x_hr &= image_subpixel_mask;
302                        y_hr &= image_subpixel_mask;
303
304                        weight = (image_subpixel_scale - x_hr) *
305                                 (image_subpixel_scale - y_hr);
306                        if(x_lr >= 0    && y_lr >= 0 &&
307                           x_lr <= maxx && y_lr <= maxy)
308                        {
309                            fg_ptr = (const value_type*)
310                                base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
311
312                            fg[0] += weight * *fg_ptr++;
313                            fg[1] += weight * *fg_ptr++;
314                            fg[2] += weight * *fg_ptr++;
315                            src_alpha += weight * base_mask;
316                        }
317                        else
318                        {
319                            fg[order_type::R] += back_r * weight;
320                            fg[order_type::G] += back_g * weight;
321                            fg[order_type::B] += back_b * weight;
322                            src_alpha         += back_a * weight;
323                        }
324
325                        x_lr++;
326
327                        weight = x_hr * (image_subpixel_scale - y_hr);
328                        if(x_lr >= 0    && y_lr >= 0 &&
329                           x_lr <= maxx && y_lr <= maxy)
330                        {
331                            fg_ptr = (const value_type*)
332                                base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
333
334                            fg[0]     += weight * *fg_ptr++;
335                            fg[1]     += weight * *fg_ptr++;
336                            fg[2]     += weight * *fg_ptr++;
337                            src_alpha += weight * base_mask;
338                        }
339                        else
340                        {
341                            fg[order_type::R] += back_r * weight;
342                            fg[order_type::G] += back_g * weight;
343                            fg[order_type::B] += back_b * weight;
344                            src_alpha         += back_a * weight;
345                        }
346
347                        x_lr--;
348                        y_lr++;
349
350                        weight = (image_subpixel_scale - x_hr) * y_hr;
351                        if(x_lr >= 0    && y_lr >= 0 &&
352                           x_lr <= maxx && y_lr <= maxy)
353                        {
354                            fg_ptr = (const value_type*)
355                                base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
356
357                            fg[0] += weight * *fg_ptr++;
358                            fg[1] += weight * *fg_ptr++;
359                            fg[2] += weight * *fg_ptr++;
360                            src_alpha += weight * base_mask;
361                        }
362                        else
363                        {
364                            fg[order_type::R] += back_r * weight;
365                            fg[order_type::G] += back_g * weight;
366                            fg[order_type::B] += back_b * weight;
367                            src_alpha         += back_a * weight;
368                        }
369
370                        x_lr++;
371
372                        weight = x_hr * y_hr;
373                        if(x_lr >= 0    && y_lr >= 0 &&
374                           x_lr <= maxx && y_lr <= maxy)
375                        {
376                            fg_ptr = (const value_type*)
377                                base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
378
379                            fg[0] += weight * *fg_ptr++;
380                            fg[1] += weight * *fg_ptr++;
381                            fg[2] += weight * *fg_ptr++;
382                            src_alpha += weight * base_mask;
383                        }
384                        else
385                        {
386                            fg[order_type::R] += back_r * weight;
387                            fg[order_type::G] += back_g * weight;
388                            fg[order_type::B] += back_b * weight;
389                            src_alpha         += back_a * weight;
390                        }
391
392                        fg[0] >>= image_subpixel_shift * 2;
393                        fg[1] >>= image_subpixel_shift * 2;
394                        fg[2] >>= image_subpixel_shift * 2;
395                        src_alpha >>= image_subpixel_shift * 2;
396                    }
397                }
398
399                span->r = (value_type)fg[order_type::R];
400                span->g = (value_type)fg[order_type::G];
401                span->b = (value_type)fg[order_type::B];
402                span->a = (value_type)src_alpha;
403                ++span;
404                ++base_type::interpolator();
405
406            } while(--len);
407        }
408    private:
409        color_type m_back_color;
410    };
411
412
413
414    //===============================================span_image_filter_rgb_2x2
415    template<class Source, class Interpolator>
416    class span_image_filter_rgb_2x2 :
417    public span_image_filter<Source, Interpolator>
418    {
419    public:
420        typedef Source source_type;
421        typedef typename source_type::color_type color_type;
422        typedef typename source_type::order_type order_type;
423        typedef Interpolator interpolator_type;
424        typedef span_image_filter<source_type, interpolator_type> base_type;
425        typedef typename color_type::value_type value_type;
426        typedef typename color_type::calc_type calc_type;
427        enum base_scale_e
428        {
429            base_shift = color_type::base_shift,
430            base_mask  = color_type::base_mask
431        };
432
433        //--------------------------------------------------------------------
434        span_image_filter_rgb_2x2() {}
435        span_image_filter_rgb_2x2(source_type& src,
436                                  interpolator_type& inter,
437                                  const image_filter_lut& filter) :
438            base_type(src, inter, &filter)
439        {}
440
441
442        //--------------------------------------------------------------------
443        void generate(color_type* span, int x, int y, unsigned len)
444        {
445            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
446                                            y + base_type::filter_dy_dbl(), len);
447
448            calc_type fg[3];
449
450            const value_type *fg_ptr;
451            const int16* weight_array = base_type::filter().weight_array() +
452                                        ((base_type::filter().diameter()/2 - 1) <<
453                                          image_subpixel_shift);
454            do
455            {
456                int x_hr;
457                int y_hr;
458
459                base_type::interpolator().coordinates(&x_hr, &y_hr);
460
461                x_hr -= base_type::filter_dx_int();
462                y_hr -= base_type::filter_dy_int();
463
464                int x_lr = x_hr >> image_subpixel_shift;
465                int y_lr = y_hr >> image_subpixel_shift;
466
467                unsigned weight;
468                fg[0] = fg[1] = fg[2] = image_filter_scale / 2;
469
470                x_hr &= image_subpixel_mask;
471                y_hr &= image_subpixel_mask;
472
473                fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
474                weight = (weight_array[x_hr + image_subpixel_scale] *
475                          weight_array[y_hr + image_subpixel_scale] +
476                          image_filter_scale / 2) >>
477                          image_filter_shift;
478                fg[0] += weight * *fg_ptr++;
479                fg[1] += weight * *fg_ptr++;
480                fg[2] += weight * *fg_ptr;
481
482                fg_ptr = (const value_type*)base_type::source().next_x();
483                weight = (weight_array[x_hr] *
484                          weight_array[y_hr + image_subpixel_scale] +
485                          image_filter_scale / 2) >>
486                          image_filter_shift;
487                fg[0] += weight * *fg_ptr++;
488                fg[1] += weight * *fg_ptr++;
489                fg[2] += weight * *fg_ptr;
490
491                fg_ptr = (const value_type*)base_type::source().next_y();
492                weight = (weight_array[x_hr + image_subpixel_scale] *
493                          weight_array[y_hr] +
494                          image_filter_scale / 2) >>
495                          image_filter_shift;
496                fg[0] += weight * *fg_ptr++;
497                fg[1] += weight * *fg_ptr++;
498                fg[2] += weight * *fg_ptr;
499
500                fg_ptr = (const value_type*)base_type::source().next_x();
501                weight = (weight_array[x_hr] *
502                          weight_array[y_hr] +
503                          image_filter_scale / 2) >>
504                          image_filter_shift;
505                fg[0] += weight * *fg_ptr++;
506                fg[1] += weight * *fg_ptr++;
507                fg[2] += weight * *fg_ptr;
508
509                fg[0] >>= image_filter_shift;
510                fg[1] >>= image_filter_shift;
511                fg[2] >>= image_filter_shift;
512
513                if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask;
514                if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask;
515                if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask;
516
517                span->r = (value_type)fg[order_type::R];
518                span->g = (value_type)fg[order_type::G];
519                span->b = (value_type)fg[order_type::B];
520                span->a = base_mask;
521
522                ++span;
523                ++base_type::interpolator();
524
525            } while(--len);
526        }
527    };
528
529
530
531    //===================================================span_image_filter_rgb
532    template<class Source, class Interpolator>
533    class span_image_filter_rgb :
534    public span_image_filter<Source, Interpolator>
535    {
536    public:
537        typedef Source source_type;
538        typedef typename source_type::color_type color_type;
539        typedef typename source_type::order_type order_type;
540        typedef Interpolator interpolator_type;
541        typedef span_image_filter<source_type, interpolator_type> base_type;
542        typedef typename color_type::value_type value_type;
543        typedef typename color_type::calc_type calc_type;
544        enum base_scale_e
545        {
546            base_shift = color_type::base_shift,
547            base_mask  = color_type::base_mask
548        };
549
550        //--------------------------------------------------------------------
551        span_image_filter_rgb() {}
552        span_image_filter_rgb(source_type& src,
553                              interpolator_type& inter,
554                              const image_filter_lut& filter) :
555            base_type(src, inter, &filter)
556        {}
557
558        //--------------------------------------------------------------------
559        void generate(color_type* span, int x, int y, unsigned len)
560        {
561            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
562                                            y + base_type::filter_dy_dbl(), len);
563
564            int fg[3];
565            const value_type *fg_ptr;
566
567            unsigned     diameter     = base_type::filter().diameter();
568            int          start        = base_type::filter().start();
569            const int16* weight_array = base_type::filter().weight_array();
570
571            int x_count;
572            int weight_y;
573
574            do
575            {
576                base_type::interpolator().coordinates(&x, &y);
577
578                x -= base_type::filter_dx_int();
579                y -= base_type::filter_dy_int();
580
581                int x_hr = x;
582                int y_hr = y;
583
584                int x_lr = x_hr >> image_subpixel_shift;
585                int y_lr = y_hr >> image_subpixel_shift;
586
587                fg[0] = fg[1] = fg[2] = image_filter_scale / 2;
588
589                int x_fract = x_hr & image_subpixel_mask;
590                unsigned y_count = diameter;
591
592                y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask);
593                fg_ptr = (const value_type*)base_type::source().span(x_lr + start,
594                                                                     y_lr + start,
595                                                                     diameter);
596                for(;;)
597                {
598                    x_count  = diameter;
599                    weight_y = weight_array[y_hr];
600                    x_hr = image_subpixel_mask - x_fract;
601                    for(;;)
602                    {
603                        int weight = (weight_y * weight_array[x_hr] +
604                                     image_filter_scale / 2) >>
605                                     image_filter_shift;
606
607                        fg[0] += weight * *fg_ptr++;
608                        fg[1] += weight * *fg_ptr++;
609                        fg[2] += weight * *fg_ptr;
610
611                        if(--x_count == 0) break;
612                        x_hr  += image_subpixel_scale;
613                        fg_ptr = (const value_type*)base_type::source().next_x();
614                    }
615
616                    if(--y_count == 0) break;
617                    y_hr  += image_subpixel_scale;
618                    fg_ptr = (const value_type*)base_type::source().next_y();
619                }
620
621                fg[0] >>= image_filter_shift;
622                fg[1] >>= image_filter_shift;
623                fg[2] >>= image_filter_shift;
624
625                if(fg[0] < 0) fg[0] = 0;
626                if(fg[1] < 0) fg[1] = 0;
627                if(fg[2] < 0) fg[2] = 0;
628
629                if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask;
630                if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask;
631                if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask;
632
633                span->r = (value_type)fg[order_type::R];
634                span->g = (value_type)fg[order_type::G];
635                span->b = (value_type)fg[order_type::B];
636                span->a = base_mask;
637
638                ++span;
639                ++base_type::interpolator();
640
641            } while(--len);
642        }
643    };
644
645
646
647    //==========================================span_image_resample_rgb_affine
648    template<class Source>
649    class span_image_resample_rgb_affine :
650    public span_image_resample_affine<Source>
651    {
652    public:
653        typedef Source source_type;
654        typedef typename source_type::color_type color_type;
655        typedef typename source_type::order_type order_type;
656        typedef span_image_resample_affine<source_type> base_type;
657        typedef typename base_type::interpolator_type interpolator_type;
658        typedef typename color_type::value_type value_type;
659        typedef typename color_type::long_type long_type;
660        enum base_scale_e
661        {
662            base_shift      = color_type::base_shift,
663            base_mask       = color_type::base_mask,
664            downscale_shift = image_filter_shift
665        };
666
667        //--------------------------------------------------------------------
668        span_image_resample_rgb_affine() {}
669        span_image_resample_rgb_affine(source_type& src,
670                                       interpolator_type& inter,
671                                       const image_filter_lut& filter) :
672            base_type(src, inter, filter)
673        {}
674
675
676        //--------------------------------------------------------------------
677        void generate(color_type* span, int x, int y, unsigned len)
678        {
679            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
680                                            y + base_type::filter_dy_dbl(), len);
681
682            long_type fg[3];
683
684            int diameter     = base_type::filter().diameter();
685            int filter_scale = diameter << image_subpixel_shift;
686            int radius_x     = (diameter * base_type::m_rx) >> 1;
687            int radius_y     = (diameter * base_type::m_ry) >> 1;
688            int len_x_lr     =
689                (diameter * base_type::m_rx + image_subpixel_mask) >>
690                    image_subpixel_shift;
691
692            const int16* weight_array = base_type::filter().weight_array();
693
694            do
695            {
696                base_type::interpolator().coordinates(&x, &y);
697
698                x += base_type::filter_dx_int() - radius_x;
699                y += base_type::filter_dy_int() - radius_y;
700
701                fg[0] = fg[1] = fg[2] = image_filter_scale / 2;
702
703                int y_lr = y >> image_subpixel_shift;
704                int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
705                                base_type::m_ry_inv) >>
706                                    image_subpixel_shift;
707                int total_weight = 0;
708                int x_lr = x >> image_subpixel_shift;
709                int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
710                                base_type::m_rx_inv) >>
711                                    image_subpixel_shift;
712
713                int x_hr2 = x_hr;
714                const value_type* fg_ptr =
715                    (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
716                for(;;)
717                {
718                    int weight_y = weight_array[y_hr];
719                    x_hr = x_hr2;
720                    for(;;)
721                    {
722                        int weight = (weight_y * weight_array[x_hr] +
723                                     image_filter_scale / 2) >>
724                                     downscale_shift;
725
726                        fg[0] += *fg_ptr++ * weight;
727                        fg[1] += *fg_ptr++ * weight;
728                        fg[2] += *fg_ptr   * weight;
729                        total_weight += weight;
730                        x_hr  += base_type::m_rx_inv;
731                        if(x_hr >= filter_scale) break;
732                        fg_ptr = (const value_type*)base_type::source().next_x();
733                    }
734                    y_hr += base_type::m_ry_inv;
735                    if(y_hr >= filter_scale) break;
736                    fg_ptr = (const value_type*)base_type::source().next_y();
737                }
738
739                fg[0] /= total_weight;
740                fg[1] /= total_weight;
741                fg[2] /= total_weight;
742
743                if(fg[0] < 0) fg[0] = 0;
744                if(fg[1] < 0) fg[1] = 0;
745                if(fg[2] < 0) fg[2] = 0;
746
747                if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask;
748                if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask;
749                if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask;
750
751                span->r = (value_type)fg[order_type::R];
752                span->g = (value_type)fg[order_type::G];
753                span->b = (value_type)fg[order_type::B];
754                span->a = base_mask;
755
756                ++span;
757                ++base_type::interpolator();
758            } while(--len);
759        }
760    };
761
762
763
764    //=================================================span_image_resample_rgb
765    template<class Source, class Interpolator>
766    class span_image_resample_rgb :
767    public span_image_resample<Source, Interpolator>
768    {
769    public:
770        typedef Source source_type;
771        typedef typename source_type::color_type color_type;
772        typedef typename source_type::order_type order_type;
773        typedef Interpolator interpolator_type;
774        typedef span_image_resample<source_type, interpolator_type> base_type;
775        typedef typename color_type::value_type value_type;
776        typedef typename color_type::long_type long_type;
777        enum base_scale_e
778        {
779            base_shift = color_type::base_shift,
780            base_mask  = color_type::base_mask,
781            downscale_shift = image_filter_shift
782        };
783
784        //--------------------------------------------------------------------
785        span_image_resample_rgb() {}
786        span_image_resample_rgb(source_type& src,
787                                interpolator_type& inter,
788                                const image_filter_lut& filter) :
789            base_type(src, inter, filter)
790        {}
791
792        //--------------------------------------------------------------------
793        void generate(color_type* span, int x, int y, unsigned len)
794        {
795            base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
796                                            y + base_type::filter_dy_dbl(), len);
797            long_type fg[3];
798
799            int diameter = base_type::filter().diameter();
800            int filter_scale = diameter << image_subpixel_shift;
801
802            const int16* weight_array = base_type::filter().weight_array();
803            do
804            {
805                int rx;
806                int ry;
807                int rx_inv = image_subpixel_scale;
808                int ry_inv = image_subpixel_scale;
809                base_type::interpolator().coordinates(&x,  &y);
810                base_type::interpolator().local_scale(&rx, &ry);
811                base_type::adjust_scale(&rx, &ry);
812
813                rx_inv = image_subpixel_scale * image_subpixel_scale / rx;
814                ry_inv = image_subpixel_scale * image_subpixel_scale / ry;
815
816                int radius_x = (diameter * rx) >> 1;
817                int radius_y = (diameter * ry) >> 1;
818                int len_x_lr =
819                    (diameter * rx + image_subpixel_mask) >>
820                        image_subpixel_shift;
821
822                x += base_type::filter_dx_int() - radius_x;
823                y += base_type::filter_dy_int() - radius_y;
824
825                fg[0] = fg[1] = fg[2] = image_filter_scale / 2;
826
827                int y_lr = y >> image_subpixel_shift;
828                int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
829                               ry_inv) >>
830                                   image_subpixel_shift;
831                int total_weight = 0;
832                int x_lr = x >> image_subpixel_shift;
833                int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
834                               rx_inv) >>
835                                   image_subpixel_shift;
836                int x_hr2 = x_hr;
837                const value_type* fg_ptr =
838                    (const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
839
840                for(;;)
841                {
842                    int weight_y = weight_array[y_hr];
843                    x_hr = x_hr2;
844                    for(;;)
845                    {
846                        int weight = (weight_y * weight_array[x_hr] +
847                                     image_filter_scale / 2) >>
848                                     downscale_shift;
849                        fg[0] += *fg_ptr++ * weight;
850                        fg[1] += *fg_ptr++ * weight;
851                        fg[2] += *fg_ptr   * weight;
852                        total_weight += weight;
853                        x_hr  += rx_inv;
854                        if(x_hr >= filter_scale) break;
855                        fg_ptr = (const value_type*)base_type::source().next_x();
856                    }
857                    y_hr += ry_inv;
858                    if(y_hr >= filter_scale) break;
859                    fg_ptr = (const value_type*)base_type::source().next_y();
860                }
861
862                fg[0] /= total_weight;
863                fg[1] /= total_weight;
864                fg[2] /= total_weight;
865
866                if(fg[0] < 0) fg[0] = 0;
867                if(fg[1] < 0) fg[1] = 0;
868                if(fg[2] < 0) fg[2] = 0;
869
870                if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask;
871                if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask;
872                if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask;
873
874                span->r = (value_type)fg[order_type::R];
875                span->g = (value_type)fg[order_type::G];
876                span->b = (value_type)fg[order_type::B];
877                span->a = base_mask;
878
879                ++span;
880                ++base_type::interpolator();
881            } while(--len);
882        }
883    };
884
885
886}
887
888
889#endif
890
891
892
893