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 
24 #ifndef AGG_PIXFMT_RGB_INCLUDED
25 #define AGG_PIXFMT_RGB_INCLUDED
26 
27 #include <string.h>
28 #include "agg_pixfmt_base.h"
29 #include "agg_rendering_buffer.h"
30 
31 namespace agg
32 {
33 
34     //=====================================================apply_gamma_dir_rgb
35     template<class ColorT, class Order, class GammaLut> class apply_gamma_dir_rgb
36     {
37     public:
38         typedef typename ColorT::value_type value_type;
39 
apply_gamma_dir_rgb(const GammaLut & gamma)40         apply_gamma_dir_rgb(const GammaLut& gamma) : m_gamma(gamma) {}
41 
operator()42         AGG_INLINE void operator () (value_type* p)
43         {
44             p[Order::R] = m_gamma.dir(p[Order::R]);
45             p[Order::G] = m_gamma.dir(p[Order::G]);
46             p[Order::B] = m_gamma.dir(p[Order::B]);
47         }
48 
49     private:
50         const GammaLut& m_gamma;
51     };
52 
53 
54 
55     //=====================================================apply_gamma_inv_rgb
56     template<class ColorT, class Order, class GammaLut> class apply_gamma_inv_rgb
57     {
58     public:
59         typedef typename ColorT::value_type value_type;
60 
apply_gamma_inv_rgb(const GammaLut & gamma)61         apply_gamma_inv_rgb(const GammaLut& gamma) : m_gamma(gamma) {}
62 
operator()63         AGG_INLINE void operator () (value_type* p)
64         {
65             p[Order::R] = m_gamma.inv(p[Order::R]);
66             p[Order::G] = m_gamma.inv(p[Order::G]);
67             p[Order::B] = m_gamma.inv(p[Order::B]);
68         }
69 
70     private:
71         const GammaLut& m_gamma;
72     };
73 
74 
75     //=========================================================blender_rgb
76     template<class ColorT, class Order>
77     struct blender_rgb
78     {
79         typedef ColorT color_type;
80         typedef Order order_type;
81         typedef typename color_type::value_type value_type;
82         typedef typename color_type::calc_type calc_type;
83         typedef typename color_type::long_type long_type;
84 
85         // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
86         // compositing function. Since the render buffer is opaque we skip the
87         // initial premultiply and final demultiply.
88 
89         //--------------------------------------------------------------------
blend_pixblender_rgb90         static AGG_INLINE void blend_pix(value_type* p,
91             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
92         {
93             blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
94         }
95 
96         //--------------------------------------------------------------------
blend_pixblender_rgb97         static AGG_INLINE void blend_pix(value_type* p,
98             value_type cr, value_type cg, value_type cb, value_type alpha)
99         {
100             p[Order::R] = color_type::lerp(p[Order::R], cr, alpha);
101             p[Order::G] = color_type::lerp(p[Order::G], cg, alpha);
102             p[Order::B] = color_type::lerp(p[Order::B], cb, alpha);
103         }
104     };
105 
106     //======================================================blender_rgb_pre
107     template<class ColorT, class Order>
108     struct blender_rgb_pre
109     {
110         typedef ColorT color_type;
111         typedef Order order_type;
112         typedef typename color_type::value_type value_type;
113         typedef typename color_type::calc_type calc_type;
114         typedef typename color_type::long_type long_type;
115 
116         // Blend pixels using the premultiplied form of Alvy-Ray Smith's
117         // compositing function.
118 
119         //--------------------------------------------------------------------
blend_pixblender_rgb_pre120         static AGG_INLINE void blend_pix(value_type* p,
121             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
122         {
123             blend_pix(p,
124                 color_type::mult_cover(cr, cover),
125                 color_type::mult_cover(cg, cover),
126                 color_type::mult_cover(cb, cover),
127                 color_type::mult_cover(alpha, cover));
128         }
129 
130         //--------------------------------------------------------------------
blend_pixblender_rgb_pre131         static AGG_INLINE void blend_pix(value_type* p,
132             value_type cr, value_type cg, value_type cb, value_type alpha)
133         {
134             p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha);
135             p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha);
136             p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha);
137         }
138     };
139 
140     //===================================================blender_rgb_gamma
141     template<class ColorT, class Order, class Gamma>
142     class blender_rgb_gamma : public blender_base<ColorT, Order>
143     {
144     public:
145         typedef ColorT color_type;
146         typedef Order order_type;
147         typedef Gamma gamma_type;
148         typedef typename color_type::value_type value_type;
149         typedef typename color_type::calc_type calc_type;
150         typedef typename color_type::long_type long_type;
151 
152         //--------------------------------------------------------------------
blender_rgb_gamma()153         blender_rgb_gamma() : m_gamma(0) {}
gamma(const gamma_type & g)154         void gamma(const gamma_type& g) { m_gamma = &g; }
155 
156         //--------------------------------------------------------------------
blend_pix(value_type * p,value_type cr,value_type cg,value_type cb,value_type alpha,cover_type cover)157         AGG_INLINE void blend_pix(value_type* p,
158             value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
159         {
160             blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
161         }
162 
163         //--------------------------------------------------------------------
blend_pix(value_type * p,value_type cr,value_type cg,value_type cb,value_type alpha)164         AGG_INLINE void blend_pix(value_type* p,
165             value_type cr, value_type cg, value_type cb, value_type alpha)
166         {
167             calc_type r = m_gamma->dir(p[Order::R]);
168             calc_type g = m_gamma->dir(p[Order::G]);
169             calc_type b = m_gamma->dir(p[Order::B]);
170             p[Order::R] = m_gamma->inv(color_type::downscale((m_gamma->dir(cr) - r) * alpha) + r);
171             p[Order::G] = m_gamma->inv(color_type::downscale((m_gamma->dir(cg) - g) * alpha) + g);
172             p[Order::B] = m_gamma->inv(color_type::downscale((m_gamma->dir(cb) - b) * alpha) + b);
173         }
174 
175     private:
176         const gamma_type* m_gamma;
177     };
178 
179 
180     //==================================================pixfmt_alpha_blend_rgb
181     template<class Blender, class RenBuf, unsigned Step, unsigned Offset = 0>
182     class pixfmt_alpha_blend_rgb
183     {
184     public:
185         typedef pixfmt_rgb_tag pixfmt_category;
186         typedef RenBuf   rbuf_type;
187         typedef Blender  blender_type;
188         typedef typename rbuf_type::row_data row_data;
189         typedef typename blender_type::color_type color_type;
190         typedef typename blender_type::order_type order_type;
191         typedef typename color_type::value_type value_type;
192         typedef typename color_type::calc_type calc_type;
193         enum
194         {
195             num_components = 3,
196             pix_step = Step,
197             pix_offset = Offset,
198             pix_width = sizeof(value_type) * pix_step
199         };
200         struct pixel_type
201         {
202             value_type c[num_components];
203 
setpixel_type204             void set(value_type r, value_type g, value_type b)
205             {
206                 c[order_type::R] = r;
207                 c[order_type::G] = g;
208                 c[order_type::B] = b;
209             }
210 
setpixel_type211             void set(const color_type& color)
212             {
213                 set(color.r, color.g, color.b);
214             }
215 
getpixel_type216             void get(value_type& r, value_type& g, value_type& b) const
217             {
218                 r = c[order_type::R];
219                 g = c[order_type::G];
220                 b = c[order_type::B];
221             }
222 
getpixel_type223             color_type get() const
224             {
225                 return color_type(
226                     c[order_type::R],
227                     c[order_type::G],
228                     c[order_type::B]);
229             }
230 
nextpixel_type231             pixel_type* next()
232             {
233                 return (pixel_type*)(c + pix_step);
234             }
235 
nextpixel_type236             const pixel_type* next() const
237             {
238                 return (const pixel_type*)(c + pix_step);
239             }
240 
advancepixel_type241             pixel_type* advance(int n)
242             {
243                 return (pixel_type*)(c + n * pix_step);
244             }
245 
advancepixel_type246             const pixel_type* advance(int n) const
247             {
248                 return (const pixel_type*)(c + n * pix_step);
249             }
250         };
251 
252     private:
253         //--------------------------------------------------------------------
blend_pix(pixel_type * p,value_type r,value_type g,value_type b,value_type a,unsigned cover)254         AGG_INLINE void blend_pix(pixel_type* p,
255             value_type r, value_type g, value_type b, value_type a,
256             unsigned cover)
257         {
258             m_blender.blend_pix(p->c, r, g, b, a, cover);
259         }
260 
261         //--------------------------------------------------------------------
blend_pix(pixel_type * p,value_type r,value_type g,value_type b,value_type a)262         AGG_INLINE void blend_pix(pixel_type* p,
263             value_type r, value_type g, value_type b, value_type a)
264         {
265             m_blender.blend_pix(p->c, r, g, b, a);
266         }
267 
268         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c,unsigned cover)269         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
270         {
271             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
272         }
273 
274         //--------------------------------------------------------------------
blend_pix(pixel_type * p,const color_type & c)275         AGG_INLINE void blend_pix(pixel_type* p, const color_type& c)
276         {
277             m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
278         }
279 
280         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c,unsigned cover)281         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover)
282         {
283             if (!c.is_transparent())
284             {
285                 if (c.is_opaque() && cover == cover_mask)
286                 {
287                     p->set(c);
288                 }
289                 else
290                 {
291                     blend_pix(p, c, cover);
292                 }
293             }
294         }
295 
296         //--------------------------------------------------------------------
copy_or_blend_pix(pixel_type * p,const color_type & c)297         AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
298         {
299             if (!c.is_transparent())
300             {
301                 if (c.is_opaque())
302                 {
303                     p->set(c);
304                 }
305                 else
306                 {
307                     blend_pix(p, c);
308                 }
309             }
310         }
311 
312     public:
313         //--------------------------------------------------------------------
pixfmt_alpha_blend_rgb(rbuf_type & rb)314         explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) :
315             m_rbuf(&rb)
316         {}
attach(rbuf_type & rb)317         void attach(rbuf_type& rb) { m_rbuf = &rb; }
318 
319         //--------------------------------------------------------------------
320         template<class PixFmt>
attach(PixFmt & pixf,int x1,int y1,int x2,int y2)321         bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
322         {
323             rect_i r(x1, y1, x2, y2);
324             if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
325             {
326                 int stride = pixf.stride();
327                 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
328                                (r.x2 - r.x1) + 1,
329                                (r.y2 - r.y1) + 1,
330                                stride);
331                 return true;
332             }
333             return false;
334         }
335 
336         //--------------------------------------------------------------------
blender()337         Blender& blender() { return m_blender; }
338 
339         //--------------------------------------------------------------------
width()340         AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
height()341         AGG_INLINE unsigned height() const { return m_rbuf->height(); }
stride()342         AGG_INLINE int      stride() const { return m_rbuf->stride(); }
343 
344         //--------------------------------------------------------------------
row_ptr(int y)345         AGG_INLINE       int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
row_ptr(int y)346         AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
row(int y)347         AGG_INLINE row_data     row(int y)     const { return m_rbuf->row(y); }
348 
349         //--------------------------------------------------------------------
pix_ptr(int x,int y)350         AGG_INLINE int8u* pix_ptr(int x, int y)
351         {
352             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
353         }
354 
pix_ptr(int x,int y)355         AGG_INLINE const int8u* pix_ptr(int x, int y) const
356         {
357             return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
358         }
359 
360         // Return pointer to pixel value, forcing row to be allocated.
pix_value_ptr(int x,int y,unsigned len)361         AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
362         {
363             return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset));
364         }
365 
366         // Return pointer to pixel value, or null if row not allocated.
pix_value_ptr(int x,int y)367         AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
368         {
369             int8u* p = m_rbuf->row_ptr(y);
370             return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0;
371         }
372 
373         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(void * p)374         AGG_INLINE static pixel_type* pix_value_ptr(void* p)
375         {
376             return (pixel_type*)((value_type*)p + pix_offset);
377         }
378 
379         // Get pixel pointer from raw buffer pointer.
pix_value_ptr(const void * p)380         AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
381         {
382             return (const pixel_type*)((const value_type*)p + pix_offset);
383         }
384 
385         //--------------------------------------------------------------------
write_plain_color(void * p,color_type c)386         AGG_INLINE static void write_plain_color(void* p, color_type c)
387         {
388             // RGB formats are implicitly premultiplied.
389             c.premultiply();
390             pix_value_ptr(p)->set(c);
391         }
392 
393         //--------------------------------------------------------------------
read_plain_color(const void * p)394         AGG_INLINE static color_type read_plain_color(const void* p)
395         {
396             return pix_value_ptr(p)->get();
397         }
398 
399         //--------------------------------------------------------------------
make_pix(int8u * p,const color_type & c)400         AGG_INLINE static void make_pix(int8u* p, const color_type& c)
401         {
402             ((pixel_type*)p)->set(c);
403         }
404 
405         //--------------------------------------------------------------------
pixel(int x,int y)406         AGG_INLINE color_type pixel(int x, int y) const
407         {
408             if (const pixel_type* p = pix_value_ptr(x, y))
409             {
410                 return p->get();
411             }
412             return color_type::no_color();
413         }
414 
415         //--------------------------------------------------------------------
copy_pixel(int x,int y,const color_type & c)416         AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
417         {
418             pix_value_ptr(x, y, 1)->set(c);
419         }
420 
421         //--------------------------------------------------------------------
blend_pixel(int x,int y,const color_type & c,int8u cover)422         AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
423         {
424             copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
425         }
426 
427         //--------------------------------------------------------------------
copy_hline(int x,int y,unsigned len,const color_type & c)428         AGG_INLINE void copy_hline(int x, int y,
429                                    unsigned len,
430                                    const color_type& c)
431         {
432             pixel_type* p = pix_value_ptr(x, y, len);
433             do
434             {
435                 p->set(c);
436                 p = p->next();
437             }
438             while(--len);
439         }
440 
441 
442         //--------------------------------------------------------------------
copy_vline(int x,int y,unsigned len,const color_type & c)443         AGG_INLINE void copy_vline(int x, int y,
444                                    unsigned len,
445                                    const color_type& c)
446         {
447             do
448             {
449                 pix_value_ptr(x, y++, 1)->set(c);
450             }
451             while (--len);
452         }
453 
454         //--------------------------------------------------------------------
blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)455         void blend_hline(int x, int y,
456                          unsigned len,
457                          const color_type& c,
458                          int8u cover)
459         {
460             if (!c.is_transparent())
461             {
462                 pixel_type* p = pix_value_ptr(x, y, len);
463 
464                 if (c.is_opaque() && cover == cover_mask)
465                 {
466                     do
467                     {
468                         p->set(c);
469                         p = p->next();
470                     }
471                     while (--len);
472                 }
473                 else
474                 {
475                     do
476                     {
477                         blend_pix(p, c, cover);
478                         p = p->next();
479                     }
480                     while (--len);
481                 }
482             }
483         }
484 
485 
486         //--------------------------------------------------------------------
blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)487         void blend_vline(int x, int y,
488                          unsigned len,
489                          const color_type& c,
490                          int8u cover)
491         {
492             if (!c.is_transparent())
493             {
494                 if (c.is_opaque() && cover == cover_mask)
495                 {
496                     do
497                     {
498                         pix_value_ptr(x, y++, 1)->set(c);
499                     }
500                     while (--len);
501                 }
502                 else
503                 {
504                     do
505                     {
506                         blend_pix(pix_value_ptr(x, y++, 1), c, cover);
507                     }
508                     while (--len);
509                 }
510             }
511         }
512 
513         //--------------------------------------------------------------------
blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)514         void blend_solid_hspan(int x, int y,
515                                unsigned len,
516                                const color_type& c,
517                                const int8u* covers)
518         {
519             if (!c.is_transparent())
520             {
521                 pixel_type* p = pix_value_ptr(x, y, len);
522 
523                 do
524                 {
525                     if (c.is_opaque() && *covers == cover_mask)
526                     {
527                         p->set(c);
528                     }
529                     else
530                     {
531                         blend_pix(p, c, *covers);
532                     }
533                     p = p->next();
534                     ++covers;
535                 }
536                 while (--len);
537             }
538         }
539 
540 
541         //--------------------------------------------------------------------
blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)542         void blend_solid_vspan(int x, int y,
543                                unsigned len,
544                                const color_type& c,
545                                const int8u* covers)
546         {
547             if (!c.is_transparent())
548             {
549                 do
550                 {
551                     pixel_type* p = pix_value_ptr(x, y++, 1);
552 
553                     if (c.is_opaque() && *covers == cover_mask)
554                     {
555                         p->set(c);
556                     }
557                     else
558                     {
559                         blend_pix(p, c, *covers);
560                     }
561                     ++covers;
562                 }
563                 while (--len);
564             }
565         }
566 
567         //--------------------------------------------------------------------
copy_color_hspan(int x,int y,unsigned len,const color_type * colors)568         void copy_color_hspan(int x, int y,
569                               unsigned len,
570                               const color_type* colors)
571         {
572             pixel_type* p = pix_value_ptr(x, y, len);
573 
574             do
575             {
576                 p->set(*colors++);
577                 p = p->next();
578             }
579             while (--len);
580         }
581 
582 
583         //--------------------------------------------------------------------
copy_color_vspan(int x,int y,unsigned len,const color_type * colors)584         void copy_color_vspan(int x, int y,
585                               unsigned len,
586                               const color_type* colors)
587         {
588             do
589             {
590                 pix_value_ptr(x, y++, 1)->set(*colors++);
591             }
592             while (--len);
593         }
594 
595         //--------------------------------------------------------------------
blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)596         void blend_color_hspan(int x, int y,
597                                unsigned len,
598                                const color_type* colors,
599                                const int8u* covers,
600                                int8u cover)
601         {
602             pixel_type* p = pix_value_ptr(x, y, len);
603 
604             if (covers)
605             {
606                 do
607                 {
608                     copy_or_blend_pix(p, *colors++, *covers++);
609                     p = p->next();
610                 }
611                 while (--len);
612             }
613             else
614             {
615                 if (cover == cover_mask)
616                 {
617                     do
618                     {
619                         copy_or_blend_pix(p, *colors++);
620                         p = p->next();
621                     }
622                     while (--len);
623                 }
624                 else
625                 {
626                     do
627                     {
628                         copy_or_blend_pix(p, *colors++, cover);
629                         p = p->next();
630                     }
631                     while (--len);
632                 }
633             }
634         }
635 
636         //--------------------------------------------------------------------
blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)637         void blend_color_vspan(int x, int y,
638                                unsigned len,
639                                const color_type* colors,
640                                const int8u* covers,
641                                int8u cover)
642         {
643             if (covers)
644             {
645                 do
646                 {
647                     copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
648                 }
649                 while (--len);
650             }
651             else
652             {
653                 if (cover == cover_mask)
654                 {
655                     do
656                     {
657                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
658                     }
659                     while (--len);
660                 }
661                 else
662                 {
663                     do
664                     {
665                         copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
666                     }
667                     while (--len);
668                 }
669             }
670         }
671 
672         //--------------------------------------------------------------------
for_each_pixel(Function f)673         template<class Function> void for_each_pixel(Function f)
674         {
675             for (unsigned y = 0; y < height(); ++y)
676             {
677                 row_data r = m_rbuf->row(y);
678                 if (r.ptr)
679                 {
680                     unsigned len = r.x2 - r.x1 + 1;
681                     pixel_type* p = pix_value_ptr(r.x1, y, len);
682                     do
683                     {
684                         f(p->c);
685                         p = p->next();
686                     }
687                     while (--len);
688                 }
689             }
690         }
691 
692         //--------------------------------------------------------------------
apply_gamma_dir(const GammaLut & g)693         template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
694         {
695             for_each_pixel(apply_gamma_dir_rgb<color_type, order_type, GammaLut>(g));
696         }
697 
698         //--------------------------------------------------------------------
apply_gamma_inv(const GammaLut & g)699         template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
700         {
701             for_each_pixel(apply_gamma_inv_rgb<color_type, order_type, GammaLut>(g));
702         }
703 
704         //--------------------------------------------------------------------
705         template<class RenBuf2>
copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)706         void copy_from(const RenBuf2& from,
707                        int xdst, int ydst,
708                        int xsrc, int ysrc,
709                        unsigned len)
710         {
711             if (const int8u* p = from.row_ptr(ysrc))
712             {
713                 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
714                         p + xsrc * pix_width,
715                         len * pix_width);
716             }
717         }
718 
719         //--------------------------------------------------------------------
720         // Blend from an RGBA surface.
721         template<class SrcPixelFormatRenderer>
blend_from(const SrcPixelFormatRenderer & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)722         void blend_from(const SrcPixelFormatRenderer& from,
723                         int xdst, int ydst,
724                         int xsrc, int ysrc,
725                         unsigned len,
726                         int8u cover)
727         {
728             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
729             typedef typename SrcPixelFormatRenderer::order_type src_order;
730 
731             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
732             {
733                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
734 
735                 if (cover == cover_mask)
736                 {
737                     do
738                     {
739                         value_type alpha = psrc->c[src_order::A];
740                         if (alpha <= color_type::empty_value())
741                         {
742                             if (alpha >= color_type::full_value())
743                             {
744                                 pdst->c[order_type::R] = psrc->c[src_order::R];
745                                 pdst->c[order_type::G] = psrc->c[src_order::G];
746                                 pdst->c[order_type::B] = psrc->c[src_order::B];
747                             }
748                             else
749                             {
750                                 blend_pix(pdst,
751                                     psrc->c[src_order::R],
752                                     psrc->c[src_order::G],
753                                     psrc->c[src_order::B],
754                                     alpha);
755                             }
756                         }
757                         psrc = psrc->next();
758                         pdst = pdst->next();
759                     }
760                     while(--len);
761                 }
762                 else
763                 {
764                     do
765                     {
766                         copy_or_blend_pix(pdst, psrc->get(), cover);
767                         psrc = psrc->next();
768                         pdst = pdst->next();
769                     }
770                     while (--len);
771                 }
772             }
773         }
774 
775         //--------------------------------------------------------------------
776         // Blend from single color, using grayscale surface as alpha channel.
777         template<class SrcPixelFormatRenderer>
blend_from_color(const SrcPixelFormatRenderer & from,const color_type & color,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)778         void blend_from_color(const SrcPixelFormatRenderer& from,
779                               const color_type& color,
780                               int xdst, int ydst,
781                               int xsrc, int ysrc,
782                               unsigned len,
783                               int8u cover)
784         {
785             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
786             typedef typename SrcPixelFormatRenderer::color_type src_color_type;
787 
788             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
789             {
790                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
791 
792                 do
793                 {
794                     copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0]));
795                     psrc = psrc->next();
796                     pdst = pdst->next();
797                 }
798                 while (--len);
799             }
800         }
801 
802         //--------------------------------------------------------------------
803         // Blend from color table, using grayscale surface as indexes into table.
804         // Obviously, this only works for integer value types.
805         template<class SrcPixelFormatRenderer>
blend_from_lut(const SrcPixelFormatRenderer & from,const color_type * color_lut,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)806         void blend_from_lut(const SrcPixelFormatRenderer& from,
807                             const color_type* color_lut,
808                             int xdst, int ydst,
809                             int xsrc, int ysrc,
810                             unsigned len,
811                             int8u cover)
812         {
813             typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
814 
815             if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
816             {
817                 pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
818 
819                 if (cover == cover_mask)
820                 {
821                     do
822                     {
823                         const color_type& color = color_lut[psrc->c[0]];
824                         blend_pix(pdst, color);
825                         psrc = psrc->next();
826                         pdst = pdst->next();
827                     }
828                     while(--len);
829                 }
830                 else
831                 {
832                     do
833                     {
834                         copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
835                         psrc = psrc->next();
836                         pdst = pdst->next();
837                     }
838                     while(--len);
839                 }
840             }
841         }
842 
843     private:
844         rbuf_type* m_rbuf;
845         Blender    m_blender;
846     };
847 
848     //-----------------------------------------------------------------------
849     typedef blender_rgb<rgba8, order_rgb> blender_rgb24;
850     typedef blender_rgb<rgba8, order_bgr> blender_bgr24;
851     typedef blender_rgb<srgba8, order_rgb> blender_srgb24;
852     typedef blender_rgb<srgba8, order_bgr> blender_sbgr24;
853     typedef blender_rgb<rgba16, order_rgb> blender_rgb48;
854     typedef blender_rgb<rgba16, order_bgr> blender_bgr48;
855     typedef blender_rgb<rgba32, order_rgb> blender_rgb96;
856     typedef blender_rgb<rgba32, order_bgr> blender_bgr96;
857 
858     typedef blender_rgb_pre<rgba8, order_rgb> blender_rgb24_pre;
859     typedef blender_rgb_pre<rgba8, order_bgr> blender_bgr24_pre;
860     typedef blender_rgb_pre<srgba8, order_rgb> blender_srgb24_pre;
861     typedef blender_rgb_pre<srgba8, order_bgr> blender_sbgr24_pre;
862     typedef blender_rgb_pre<rgba16, order_rgb> blender_rgb48_pre;
863     typedef blender_rgb_pre<rgba16, order_bgr> blender_bgr48_pre;
864     typedef blender_rgb_pre<rgba32, order_rgb> blender_rgb96_pre;
865     typedef blender_rgb_pre<rgba32, order_bgr> blender_bgr96_pre;
866 
867     typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 3> pixfmt_rgb24;
868     typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 3> pixfmt_bgr24;
869     typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 3> pixfmt_srgb24;
870     typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 3> pixfmt_sbgr24;
871     typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 3> pixfmt_rgb48;
872     typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 3> pixfmt_bgr48;
873     typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 3> pixfmt_rgb96;
874     typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 3> pixfmt_bgr96;
875 
876     typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 3> pixfmt_rgb24_pre;
877     typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 3> pixfmt_bgr24_pre;
878     typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 3> pixfmt_srgb24_pre;
879     typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 3> pixfmt_sbgr24_pre;
880     typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 3> pixfmt_rgb48_pre;
881     typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 3> pixfmt_bgr48_pre;
882     typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 3> pixfmt_rgb96_pre;
883     typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 3> pixfmt_bgr96_pre;
884 
885     typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 4, 0> pixfmt_rgbx32;
886     typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 4, 1> pixfmt_xrgb32;
887     typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 4, 1> pixfmt_xbgr32;
888     typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 4, 0> pixfmt_bgrx32;
889     typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 4, 0> pixfmt_srgbx32;
890     typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 4, 1> pixfmt_sxrgb32;
891     typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 4, 1> pixfmt_sxbgr32;
892     typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 4, 0> pixfmt_sbgrx32;
893     typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 4, 0> pixfmt_rgbx64;
894     typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 4, 1> pixfmt_xrgb64;
895     typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 4, 1> pixfmt_xbgr64;
896     typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 4, 0> pixfmt_bgrx64;
897     typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 4, 0> pixfmt_rgbx128;
898     typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 4, 1> pixfmt_xrgb128;
899     typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 4, 1> pixfmt_xbgr128;
900     typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 4, 0> pixfmt_bgrx128;
901 
902     typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 4, 0> pixfmt_rgbx32_pre;
903     typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 4, 1> pixfmt_xrgb32_pre;
904     typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 4, 1> pixfmt_xbgr32_pre;
905     typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 4, 0> pixfmt_bgrx32_pre;
906     typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 4, 0> pixfmt_srgbx32_pre;
907     typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 4, 1> pixfmt_sxrgb32_pre;
908     typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 4, 1> pixfmt_sxbgr32_pre;
909     typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 4, 0> pixfmt_sbgrx32_pre;
910     typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 4, 0> pixfmt_rgbx64_pre;
911     typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 4, 1> pixfmt_xrgb64_pre;
912     typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 4, 1> pixfmt_xbgr64_pre;
913     typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 4, 0> pixfmt_bgrx64_pre;
914     typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 4, 0> pixfmt_rgbx128_pre;
915     typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 4, 1> pixfmt_xrgb128_pre;
916     typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 4, 1> pixfmt_xbgr128_pre;
917     typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 4, 0> pixfmt_bgrx128_pre;
918 
919 
920     //-----------------------------------------------------pixfmt_rgb24_gamma
921     template<class Gamma> class pixfmt_rgb24_gamma :
922     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer, 3>
923     {
924     public:
pixfmt_rgb24_gamma(rendering_buffer & rb,const Gamma & g)925         pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) :
926             pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer, 3>(rb)
927         {
928             this->blender().gamma(g);
929         }
930     };
931 
932     //-----------------------------------------------------pixfmt_srgb24_gamma
933     template<class Gamma> class pixfmt_srgb24_gamma :
934     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_rgb, Gamma>, rendering_buffer, 3>
935     {
936     public:
pixfmt_srgb24_gamma(rendering_buffer & rb,const Gamma & g)937         pixfmt_srgb24_gamma(rendering_buffer& rb, const Gamma& g) :
938             pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_rgb, Gamma>, rendering_buffer, 3>(rb)
939         {
940             this->blender().gamma(g);
941         }
942     };
943 
944     //-----------------------------------------------------pixfmt_bgr24_gamma
945     template<class Gamma> class pixfmt_bgr24_gamma :
946     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer, 3>
947     {
948     public:
pixfmt_bgr24_gamma(rendering_buffer & rb,const Gamma & g)949         pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) :
950             pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer, 3>(rb)
951         {
952             this->blender().gamma(g);
953         }
954     };
955 
956     //-----------------------------------------------------pixfmt_sbgr24_gamma
957     template<class Gamma> class pixfmt_sbgr24_gamma :
958     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_bgr, Gamma>, rendering_buffer, 3>
959     {
960     public:
pixfmt_sbgr24_gamma(rendering_buffer & rb,const Gamma & g)961         pixfmt_sbgr24_gamma(rendering_buffer& rb, const Gamma& g) :
962             pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_bgr, Gamma>, rendering_buffer, 3>(rb)
963         {
964             this->blender().gamma(g);
965         }
966     };
967 
968     //-----------------------------------------------------pixfmt_rgb48_gamma
969     template<class Gamma> class pixfmt_rgb48_gamma :
970     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer, 3>
971     {
972     public:
pixfmt_rgb48_gamma(rendering_buffer & rb,const Gamma & g)973         pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) :
974             pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer, 3>(rb)
975         {
976             this->blender().gamma(g);
977         }
978     };
979 
980     //-----------------------------------------------------pixfmt_bgr48_gamma
981     template<class Gamma> class pixfmt_bgr48_gamma :
982     public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer, 3>
983     {
984     public:
pixfmt_bgr48_gamma(rendering_buffer & rb,const Gamma & g)985         pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) :
986             pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer, 3>(rb)
987         {
988             this->blender().gamma(g);
989         }
990     };
991 
992 }
993 
994 #endif
995 
996