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