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