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_GRAY_INCLUDED
25#define AGG_PIXFMT_GRAY_INCLUDED
26
27#include <string.h>
28#include "agg_basics.h"
29#include "agg_color_gray.h"
30#include "agg_rendering_buffer.h"
31
32namespace agg
33{
34
35    //============================================================blender_gray
36    template<class ColorT> struct blender_gray
37    {
38        typedef ColorT color_type;
39        typedef typename color_type::value_type value_type;
40        typedef typename color_type::calc_type calc_type;
41        enum base_scale_e { base_shift = color_type::base_shift };
42
43        static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
44                                         unsigned alpha, unsigned cover=0)
45        {
46            *p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift);
47        }
48    };
49
50
51    //======================================================blender_gray_pre
52    template<class ColorT> struct blender_gray_pre
53    {
54        typedef ColorT color_type;
55        typedef typename color_type::value_type value_type;
56        typedef typename color_type::calc_type calc_type;
57        enum base_scale_e { base_shift = color_type::base_shift };
58
59        static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
60                                         unsigned alpha, unsigned cover)
61        {
62            alpha = color_type::base_mask - alpha;
63            cover = (cover + 1) << (base_shift - 8);
64            *p = (value_type)((*p * alpha + cv * cover) >> base_shift);
65        }
66
67        static AGG_INLINE void blend_pix(value_type* p, unsigned cv,
68                                         unsigned alpha)
69        {
70            *p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv);
71        }
72    };
73
74
75
76    //=====================================================apply_gamma_dir_gray
77    template<class ColorT, class GammaLut> class apply_gamma_dir_gray
78    {
79    public:
80        typedef typename ColorT::value_type value_type;
81
82        apply_gamma_dir_gray(const GammaLut& gamma) : m_gamma(gamma) {}
83
84        AGG_INLINE void operator () (value_type* p)
85        {
86            *p = m_gamma.dir(*p);
87        }
88
89    private:
90        const GammaLut& m_gamma;
91    };
92
93
94
95    //=====================================================apply_gamma_inv_gray
96    template<class ColorT, class GammaLut> class apply_gamma_inv_gray
97    {
98    public:
99        typedef typename ColorT::value_type value_type;
100
101        apply_gamma_inv_gray(const GammaLut& gamma) : m_gamma(gamma) {}
102
103        AGG_INLINE void operator () (value_type* p)
104        {
105            *p = m_gamma.inv(*p);
106        }
107
108    private:
109        const GammaLut& m_gamma;
110    };
111
112
113
114    //=================================================pixfmt_alpha_blend_gray
115    template<class Blender, class RenBuf, unsigned Step=1, unsigned Offset=0>
116    class pixfmt_alpha_blend_gray
117    {
118    public:
119        typedef RenBuf   rbuf_type;
120        typedef typename rbuf_type::row_data row_data;
121        typedef Blender  blender_type;
122        typedef typename blender_type::color_type color_type;
123        typedef int                               order_type; // A fake one
124        typedef typename color_type::value_type   value_type;
125        typedef typename color_type::calc_type    calc_type;
126        enum base_scale_e
127        {
128            base_shift = color_type::base_shift,
129            base_scale = color_type::base_scale,
130            base_mask  = color_type::base_mask,
131            pix_width  = sizeof(value_type),
132            pix_step   = Step,
133            pix_offset = Offset
134        };
135
136    private:
137        //--------------------------------------------------------------------
138        static AGG_INLINE void copy_or_blend_pix(value_type* p,
139                                                 const color_type& c,
140                                                 unsigned cover)
141        {
142            if (c.a)
143            {
144                calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
145                if(alpha == base_mask)
146                {
147                    *p = c.v;
148                }
149                else
150                {
151                    Blender::blend_pix(p, c.v, alpha, cover);
152                }
153            }
154        }
155
156
157        static AGG_INLINE void copy_or_blend_pix(value_type* p,
158                                                 const color_type& c)
159        {
160            if (c.a)
161            {
162                if(c.a == base_mask)
163                {
164                    *p = c.v;
165                }
166                else
167                {
168                    Blender::blend_pix(p, c.v, c.a);
169                }
170            }
171        }
172
173
174    public:
175        //--------------------------------------------------------------------
176        pixfmt_alpha_blend_gray(rbuf_type& rb) :
177            m_rbuf(&rb)
178        {}
179        void attach(rbuf_type& rb) { m_rbuf = &rb; }
180        //--------------------------------------------------------------------
181
182        template<class PixFmt>
183        bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
184        {
185            rect_i r(x1, y1, x2, y2);
186            if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
187            {
188                int stride = pixf.stride();
189                m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
190                               (r.x2 - r.x1) + 1,
191                               (r.y2 - r.y1) + 1,
192                               stride);
193                return true;
194            }
195            return false;
196        }
197
198        //--------------------------------------------------------------------
199        AGG_INLINE unsigned width()  const { return m_rbuf->width();  }
200        AGG_INLINE unsigned height() const { return m_rbuf->height(); }
201        AGG_INLINE int      stride() const { return m_rbuf->stride(); }
202
203        //--------------------------------------------------------------------
204              int8u* row_ptr(int y)       { return m_rbuf->row_ptr(y); }
205        const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
206        row_data     row(int y)     const { return m_rbuf->row(y); }
207
208        const int8u* pix_ptr(int x, int y) const
209        {
210            return m_rbuf->row_ptr(y) + x * Step + Offset;
211        }
212
213        int8u* pix_ptr(int x, int y)
214        {
215            return m_rbuf->row_ptr(y) + x * Step + Offset;
216        }
217
218        //--------------------------------------------------------------------
219        AGG_INLINE static void make_pix(int8u* p, const color_type& c)
220        {
221            *(value_type*)p = c.v;
222        }
223
224        //--------------------------------------------------------------------
225        AGG_INLINE color_type pixel(int x, int y) const
226        {
227            value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset;
228            return color_type(*p);
229        }
230
231        //--------------------------------------------------------------------
232        AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
233        {
234            *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v;
235        }
236
237        //--------------------------------------------------------------------
238        AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
239        {
240            copy_or_blend_pix((value_type*)
241                               m_rbuf->row_ptr(x, y, 1) + x * Step + Offset,
242                               c,
243                               cover);
244        }
245
246
247        //--------------------------------------------------------------------
248        AGG_INLINE void copy_hline(int x, int y,
249                                   unsigned len,
250                                   const color_type& c)
251        {
252            value_type* p = (value_type*)
253                m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
254
255            do
256            {
257                *p = c.v;
258                p += Step;
259            }
260            while(--len);
261        }
262
263
264        //--------------------------------------------------------------------
265        AGG_INLINE void copy_vline(int x, int y,
266                                   unsigned len,
267                                   const color_type& c)
268        {
269            do
270            {
271                value_type* p = (value_type*)
272                    m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
273
274                *p = c.v;
275            }
276            while(--len);
277        }
278
279
280        //--------------------------------------------------------------------
281        void blend_hline(int x, int y,
282                         unsigned len,
283                         const color_type& c,
284                         int8u cover)
285        {
286            if (c.a)
287            {
288                value_type* p = (value_type*)
289                    m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
290
291                calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
292                if(alpha == base_mask)
293                {
294                    do
295                    {
296                        *p = c.v;
297                        p += Step;
298                    }
299                    while(--len);
300                }
301                else
302                {
303                    do
304                    {
305                        Blender::blend_pix(p, c.v, alpha, cover);
306                        p += Step;
307                    }
308                    while(--len);
309                }
310            }
311        }
312
313
314        //--------------------------------------------------------------------
315        void blend_vline(int x, int y,
316                         unsigned len,
317                         const color_type& c,
318                         int8u cover)
319        {
320            if (c.a)
321            {
322                value_type* p;
323                calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
324                if(alpha == base_mask)
325                {
326                    do
327                    {
328                        p = (value_type*)
329                            m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
330
331                        *p = c.v;
332                    }
333                    while(--len);
334                }
335                else
336                {
337                    do
338                    {
339                        p = (value_type*)
340                            m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
341
342                        Blender::blend_pix(p, c.v, alpha, cover);
343                    }
344                    while(--len);
345                }
346            }
347        }
348
349
350        //--------------------------------------------------------------------
351        void blend_solid_hspan(int x, int y,
352                               unsigned len,
353                               const color_type& c,
354                               const int8u* covers)
355        {
356            if (c.a)
357            {
358                value_type* p = (value_type*)
359                    m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
360
361                do
362                {
363                    calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
364                    if(alpha == base_mask)
365                    {
366                        *p = c.v;
367                    }
368                    else
369                    {
370                        Blender::blend_pix(p, c.v, alpha, *covers);
371                    }
372                    p += Step;
373                    ++covers;
374                }
375                while(--len);
376            }
377        }
378
379
380        //--------------------------------------------------------------------
381        void blend_solid_vspan(int x, int y,
382                               unsigned len,
383                               const color_type& c,
384                               const int8u* covers)
385        {
386            if (c.a)
387            {
388                do
389                {
390                    calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
391
392                    value_type* p = (value_type*)
393                        m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
394
395                    if(alpha == base_mask)
396                    {
397                        *p = c.v;
398                    }
399                    else
400                    {
401                        Blender::blend_pix(p, c.v, alpha, *covers);
402                    }
403                    ++covers;
404                }
405                while(--len);
406            }
407        }
408
409
410        //--------------------------------------------------------------------
411        void copy_color_hspan(int x, int y,
412                              unsigned len,
413                              const color_type* colors)
414        {
415            value_type* p = (value_type*)
416                m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
417
418            do
419            {
420                *p = colors->v;
421                p += Step;
422                ++colors;
423            }
424            while(--len);
425        }
426
427
428        //--------------------------------------------------------------------
429        void copy_color_vspan(int x, int y,
430                              unsigned len,
431                              const color_type* colors)
432        {
433            do
434            {
435                value_type* p = (value_type*)
436                    m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
437                *p = colors->v;
438                ++colors;
439            }
440            while(--len);
441        }
442
443
444        //--------------------------------------------------------------------
445        void blend_color_hspan(int x, int y,
446                               unsigned len,
447                               const color_type* colors,
448                               const int8u* covers,
449                               int8u cover)
450        {
451            value_type* p = (value_type*)
452                m_rbuf->row_ptr(x, y, len) + x * Step + Offset;
453
454            if(covers)
455            {
456                do
457                {
458                    copy_or_blend_pix(p, *colors++, *covers++);
459                    p += Step;
460                }
461                while(--len);
462            }
463            else
464            {
465                if(cover == 255)
466                {
467                    do
468                    {
469                        if(colors->a == base_mask)
470                        {
471                            *p = colors->v;
472                        }
473                        else
474                        {
475                            copy_or_blend_pix(p, *colors);
476                        }
477                        p += Step;
478                        ++colors;
479                    }
480                    while(--len);
481                }
482                else
483                {
484                    do
485                    {
486                        copy_or_blend_pix(p, *colors++, cover);
487                        p += Step;
488                    }
489                    while(--len);
490                }
491            }
492        }
493
494
495
496        //--------------------------------------------------------------------
497        void blend_color_vspan(int x, int y,
498                               unsigned len,
499                               const color_type* colors,
500                               const int8u* covers,
501                               int8u cover)
502        {
503            value_type* p;
504            if(covers)
505            {
506                do
507                {
508                    p = (value_type*)
509                        m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
510
511                    copy_or_blend_pix(p, *colors++, *covers++);
512                }
513                while(--len);
514            }
515            else
516            {
517                if(cover == 255)
518                {
519                    do
520                    {
521                        p = (value_type*)
522                            m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
523
524                        if(colors->a == base_mask)
525                        {
526                            *p = colors->v;
527                        }
528                        else
529                        {
530                            copy_or_blend_pix(p, *colors);
531                        }
532                        ++colors;
533                    }
534                    while(--len);
535                }
536                else
537                {
538                    do
539                    {
540                        p = (value_type*)
541                            m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset;
542
543                        copy_or_blend_pix(p, *colors++, cover);
544                    }
545                    while(--len);
546                }
547            }
548        }
549
550        //--------------------------------------------------------------------
551        template<class Function> void for_each_pixel(Function f)
552        {
553            unsigned y;
554            for(y = 0; y < height(); ++y)
555            {
556                row_data r = m_rbuf->row(y);
557                if(r.ptr)
558                {
559                    unsigned len = r.x2 - r.x1 + 1;
560
561                    value_type* p = (value_type*)
562                        m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset;
563
564                    do
565                    {
566                        f(p);
567                        p += Step;
568                    }
569                    while(--len);
570                }
571            }
572        }
573
574        //--------------------------------------------------------------------
575        template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
576        {
577            for_each_pixel(apply_gamma_dir_gray<color_type, GammaLut>(g));
578        }
579
580        //--------------------------------------------------------------------
581        template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
582        {
583            for_each_pixel(apply_gamma_inv_gray<color_type, GammaLut>(g));
584        }
585
586        //--------------------------------------------------------------------
587        template<class RenBuf2>
588        void copy_from(const RenBuf2& from,
589                       int xdst, int ydst,
590                       int xsrc, int ysrc,
591                       unsigned len)
592        {
593            const int8u* p = from.row_ptr(ysrc);
594            if(p)
595            {
596                memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
597                        p + xsrc * pix_width,
598                        len * pix_width);
599            }
600        }
601
602    private:
603        rbuf_type* m_rbuf;
604    };
605
606    typedef blender_gray<gray8>      blender_gray8;
607    typedef blender_gray_pre<gray8>  blender_gray8_pre;
608    typedef blender_gray<gray16>     blender_gray16;
609    typedef blender_gray_pre<gray16> blender_gray16_pre;
610
611    typedef pixfmt_alpha_blend_gray<blender_gray8,      rendering_buffer> pixfmt_gray8;      //----pixfmt_gray8
612    typedef pixfmt_alpha_blend_gray<blender_gray8_pre,  rendering_buffer> pixfmt_gray8_pre;  //----pixfmt_gray8_pre
613    typedef pixfmt_alpha_blend_gray<blender_gray16,     rendering_buffer> pixfmt_gray16;     //----pixfmt_gray16
614    typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; //----pixfmt_gray16_pre
615}
616
617#endif
618
619