//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software 
// is granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//----------------------------------------------------------------------------
//
// Adaptation for high precision colors has been sponsored by 
// Liberty Technology Systems, Inc., visit http://lib-sys.com
//
// Liberty Technology Systems, Inc. is the provider of
// PostScript and PDF technology for software developers.
// 
//----------------------------------------------------------------------------
//
// color types gray8, gray16
//
//----------------------------------------------------------------------------

#ifndef AGG_COLOR_GRAY_INCLUDED
#define AGG_COLOR_GRAY_INCLUDED

#include "agg_basics.h"
#include "agg_color_rgba.h"

namespace agg
{

    //===================================================================gray8
    template<class Colorspace>
    struct gray8T
    {
        typedef int8u  value_type;
        typedef int32u calc_type;
        typedef int32  long_type;
        enum base_scale_e
        {
            base_shift = 8,
            base_scale = 1 << base_shift,
            base_mask  = base_scale - 1,
            base_MSB = 1 << (base_shift - 1)
        };
        typedef gray8T self_type;

        value_type v;
        value_type a;

        static value_type luminance(const rgba& c)
        {
            // Calculate grayscale value as per ITU-R BT.709.
            return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask));
        }

        static value_type luminance(const rgba8& c)
        {
            // Calculate grayscale value as per ITU-R BT.709.
            return value_type((55u * c.r + 184u * c.g + 18u * c.b) >> 8);
        }

        static void convert(gray8T<linear>& dst, const gray8T<sRGB>& src)
        {
            dst.v = sRGB_conv<value_type>::rgb_from_sRGB(src.v);
            dst.a = src.a;
        }

        static void convert(gray8T<sRGB>& dst, const gray8T<linear>& src)
        {
            dst.v = sRGB_conv<value_type>::rgb_to_sRGB(src.v);
            dst.a = src.a;
        }

        static void convert(gray8T<linear>& dst, const rgba8& src)
        {
            dst.v = luminance(src);
            dst.a = src.a;
        }

        static void convert(gray8T<linear>& dst, const srgba8& src)
        {
            // The RGB weights are only valid for linear values.
            convert(dst, rgba8(src));
        }

        static void convert(gray8T<sRGB>& dst, const rgba8& src)
        {
            dst.v = sRGB_conv<value_type>::rgb_to_sRGB(luminance(src));
            dst.a = src.a;
        }

        static void convert(gray8T<sRGB>& dst, const srgba8& src)
        {
            // The RGB weights are only valid for linear values.
            convert(dst, rgba8(src));
        }

        //--------------------------------------------------------------------
        gray8T() {}

        //--------------------------------------------------------------------
        explicit gray8T(unsigned v_, unsigned a_ = base_mask) :
            v(int8u(v_)), a(int8u(a_)) {}

        //--------------------------------------------------------------------
        gray8T(const self_type& c, unsigned a_) :
            v(c.v), a(value_type(a_)) {}

        //--------------------------------------------------------------------
        gray8T(const rgba& c) :
            v(luminance(c)),
            a(value_type(uround(c.a * base_mask))) {}

        //--------------------------------------------------------------------
        template<class T>
        gray8T(const gray8T<T>& c)
        {
            convert(*this, c);
        }

        //--------------------------------------------------------------------
        template<class T>
        gray8T(const rgba8T<T>& c)
        {
            convert(*this, c);
        }

        //--------------------------------------------------------------------
        template<class T> 
        T convert_from_sRGB() const 
        {
            typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_from_sRGB(v);
            return T(y, y, y, sRGB_conv<typename T::value_type>::alpha_from_sRGB(a));
        }

        template<class T> 
        T convert_to_sRGB() const 
        {
            typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_to_sRGB(v);
            return T(y, y, y, sRGB_conv<typename T::value_type>::alpha_to_sRGB(a));
        }

        //--------------------------------------------------------------------
        rgba8 make_rgba8(const linear&) const 
        {
            return rgba8(v, v, v, a);
        }

        rgba8 make_rgba8(const sRGB&) const 
        {
            return convert_from_sRGB<srgba8>();
        }

        operator rgba8() const 
        {
            return make_rgba8(Colorspace());
        }

        //--------------------------------------------------------------------
        srgba8 make_srgba8(const linear&) const 
        {
            return convert_to_sRGB<rgba8>();
        }

        srgba8 make_srgba8(const sRGB&) const 
        {
            return srgba8(v, v, v, a);
        }

        operator srgba8() const 
        {
            return make_rgba8(Colorspace());
        }

        //--------------------------------------------------------------------
        rgba16 make_rgba16(const linear&) const 
        {
            rgba16::value_type rgb = (v << 8) | v;
            return rgba16(rgb, rgb, rgb, (a << 8) | a);
        }

        rgba16 make_rgba16(const sRGB&) const 
        {
            return convert_from_sRGB<rgba16>();
        }

        operator rgba16() const 
        {
            return make_rgba16(Colorspace());
        }

        //--------------------------------------------------------------------
        rgba32 make_rgba32(const linear&) const 
        {
            rgba32::value_type v32 = v / 255.0f;
            return rgba32(v32, v32, v32, a / 255.0f);
        }

        rgba32 make_rgba32(const sRGB&) const 
        {
            return convert_from_sRGB<rgba32>();
        }

        operator rgba32() const 
        {
            return make_rgba32(Colorspace());
        }

        //--------------------------------------------------------------------
        static AGG_INLINE double to_double(value_type a)
        {
            return double(a) / base_mask;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type from_double(double a)
        {
            return value_type(uround(a * base_mask));
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type empty_value()
        {
            return 0;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type full_value()
        {
            return base_mask;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_transparent() const
        {
            return a == 0;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_opaque() const
        {
            return a == base_mask;
        }

        //--------------------------------------------------------------------
        // Fixed-point multiply, exact over int8u.
        static AGG_INLINE value_type multiply(value_type a, value_type b) 
        {
            calc_type t = a * b + base_MSB;
            return value_type(((t >> base_shift) + t) >> base_shift);
        }
        
        //--------------------------------------------------------------------
        static AGG_INLINE value_type demultiply(value_type a, value_type b) 
        {
            if (a * b == 0)
            {
                return 0;
            }
            else if (a >= b)
            {
                return base_mask;
            }
            else return value_type((a * base_mask + (b >> 1)) / b); 
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downscale(T a) 
        {
            return a >> base_shift;
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downshift(T a, unsigned n) 
        {
            return a >> n;
        }

        //--------------------------------------------------------------------
        // Fixed-point multiply, exact over int8u.
        // Specifically for multiplying a color component by a cover.
        static AGG_INLINE value_type mult_cover(value_type a, value_type b) 
        {
            return multiply(a, b);
        }
        
        //--------------------------------------------------------------------
        static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) 
        {
            return multiply(b, a);
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a, assuming q is premultiplied by a.
        static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) 
        {
            return p + q - multiply(p, a);
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a.
        static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) 
        {
            int t = (q - p) * a + base_MSB - (p > q);
            return value_type(p + (((t >> base_shift) + t) >> base_shift));
        }
        
        //--------------------------------------------------------------------
        self_type& clear()
        {
            v = a = 0;
			return *this;
        }

        //--------------------------------------------------------------------
        self_type& transparent()
        {
            a = 0;
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& opacity(double a_)
        {
            if (a_ < 0) a = 0;
            else if (a_ > 1) a = 1;
            else a = (value_type)uround(a_ * double(base_mask));
			return *this;
        }

        //--------------------------------------------------------------------
        double opacity() const
        {
            return double(a) / double(base_mask);
        }
        
        //--------------------------------------------------------------------
        self_type& premultiply()
        {
            if (a < base_mask)
            {
                if (a == 0) v = 0;
                else v = multiply(v, a);
            }
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& demultiply()
        {
            if (a < base_mask)
            {
                if (a == 0)
                {
                    v = 0;
                }
                else
                {
                    calc_type v_ = (calc_type(v) * base_mask) / a;
                    v = value_type((v_ > base_mask) ? (value_type)base_mask : v_);
                }
            }
            return *this;
        }

        //--------------------------------------------------------------------
        self_type gradient(self_type c, double k) const
        {
            self_type ret;
            calc_type ik = uround(k * base_scale);
            ret.v = lerp(v, c.v, ik);
            ret.a = lerp(a, c.a, ik);
            return ret;
        }

        //--------------------------------------------------------------------
        AGG_INLINE void add(const self_type& c, unsigned cover)
        {
            calc_type cv, ca;
            if (cover == cover_mask)
            {
                if (c.a == base_mask) 
                {
                    *this = c;
                    return;
                }
                else
                {
                    cv = v + c.v; 
                    ca = a + c.a; 
                }
            }
            else
            {
                cv = v + mult_cover(c.v, cover);
                ca = a + mult_cover(c.a, cover);
            }
            v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv);
            a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca);
        }

        //--------------------------------------------------------------------
        static self_type no_color() { return self_type(0,0); }
    };

    typedef gray8T<linear> gray8;
    typedef gray8T<sRGB> sgray8;


    //==================================================================gray16
    struct gray16
    {
        typedef int16u value_type;
        typedef int32u calc_type;
        typedef int64  long_type;
        enum base_scale_e
        {
            base_shift = 16,
            base_scale = 1 << base_shift,
            base_mask  = base_scale - 1,
            base_MSB = 1 << (base_shift - 1)
        };
        typedef gray16 self_type;

        value_type v;
        value_type a;

        static value_type luminance(const rgba& c)
        {
            // Calculate grayscale value as per ITU-R BT.709.
            return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask));
        }

        static value_type luminance(const rgba16& c)
        {
            // Calculate grayscale value as per ITU-R BT.709.
            return value_type((13933u * c.r + 46872u * c.g + 4732u * c.b) >> 16);
        }

        static value_type luminance(const rgba8& c)
        {
            return luminance(rgba16(c));
        }

        static value_type luminance(const srgba8& c)
        {
            return luminance(rgba16(c));
        }

        static value_type luminance(const rgba32& c)
        {
            return luminance(rgba(c));
        }

        //--------------------------------------------------------------------
        gray16() {}

        //--------------------------------------------------------------------
        explicit gray16(unsigned v_, unsigned a_ = base_mask) :
            v(int16u(v_)), a(int16u(a_)) {}

        //--------------------------------------------------------------------
        gray16(const self_type& c, unsigned a_) :
            v(c.v), a(value_type(a_)) {}

        //--------------------------------------------------------------------
        gray16(const rgba& c) :
            v(luminance(c)),
            a((value_type)uround(c.a * double(base_mask))) {}

        //--------------------------------------------------------------------
        gray16(const rgba8& c) :
            v(luminance(c)),
            a((value_type(c.a) << 8) | c.a) {}

        //--------------------------------------------------------------------
        gray16(const srgba8& c) :
            v(luminance(c)),
            a((value_type(c.a) << 8) | c.a) {}

        //--------------------------------------------------------------------
        gray16(const rgba16& c) :
            v(luminance(c)),
            a(c.a) {}
        
        //--------------------------------------------------------------------
        gray16(const gray8& c) :
            v((value_type(c.v) << 8) | c.v),
            a((value_type(c.a) << 8) | c.a) {}

        //--------------------------------------------------------------------
        gray16(const sgray8& c) :
            v(sRGB_conv<value_type>::rgb_from_sRGB(c.v)),
            a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {}

        //--------------------------------------------------------------------
        operator rgba8() const 
        {
            return rgba8(v >> 8, v >> 8, v >> 8, a >> 8);
        }

        //--------------------------------------------------------------------
        operator srgba8() const 
        {
            value_type y = sRGB_conv<value_type>::rgb_to_sRGB(v);
            return srgba8(y, y, y, sRGB_conv<value_type>::alpha_to_sRGB(a));
        }

        //--------------------------------------------------------------------
        operator rgba16() const 
        {
            return rgba16(v, v, v, a);
        }

		//--------------------------------------------------------------------
		operator rgba32() const
		{
			rgba32::value_type v32 = v / 65535.0f;
			return rgba32(v32, v32, v32, a / 65535.0f);
		}

		//--------------------------------------------------------------------
        operator gray8() const 
        {
            return gray8(v >> 8, a >> 8);
        }

        //--------------------------------------------------------------------
        operator sgray8() const 
        {
            return sgray8(
                sRGB_conv<value_type>::rgb_to_sRGB(v), 
                sRGB_conv<value_type>::alpha_to_sRGB(a));
        }

        //--------------------------------------------------------------------
        static AGG_INLINE double to_double(value_type a)
        {
            return double(a) / base_mask;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type from_double(double a)
        {
            return value_type(uround(a * base_mask));
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type empty_value()
        {
            return 0;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type full_value()
        {
            return base_mask;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_transparent() const
        {
            return a == 0;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_opaque() const
        {
            return a == base_mask;
        }

        //--------------------------------------------------------------------
        // Fixed-point multiply, exact over int16u.
        static AGG_INLINE value_type multiply(value_type a, value_type b) 
        {
            calc_type t = a * b + base_MSB;
            return value_type(((t >> base_shift) + t) >> base_shift);
        }
        
        //--------------------------------------------------------------------
        static AGG_INLINE value_type demultiply(value_type a, value_type b) 
        {
            if (a * b == 0)
            {
                return 0;
            }
            else if (a >= b)
            {
                return base_mask;
            }
            else return value_type((a * base_mask + (b >> 1)) / b); 
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downscale(T a) 
        {
            return a >> base_shift;
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downshift(T a, unsigned n) 
        {
            return a >> n;
        }

        //--------------------------------------------------------------------
        // Fixed-point multiply, almost exact over int16u.
        // Specifically for multiplying a color component by a cover.
        static AGG_INLINE value_type mult_cover(value_type a, cover_type b) 
        {
            return multiply(a, b << 8 | b);
        }
        
        //--------------------------------------------------------------------
        static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) 
        {
            return mult_cover(b, a) >> 8;
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a, assuming q is premultiplied by a.
        static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) 
        {
            return p + q - multiply(p, a);
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a.
        static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) 
        {
            int t = (q - p) * a + base_MSB - (p > q);
            return value_type(p + (((t >> base_shift) + t) >> base_shift));
        }
        
        //--------------------------------------------------------------------
        self_type& clear()
        {
            v = a = 0;
			return *this;
        }

        //--------------------------------------------------------------------
        self_type& transparent()
        {
            a = 0;
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& opacity(double a_)
        {
            if (a_ < 0) a = 0;
            else if(a_ > 1) a = 1;
            else a = (value_type)uround(a_ * double(base_mask));
			return *this;
        }

        //--------------------------------------------------------------------
        double opacity() const
        {
            return double(a) / double(base_mask);
        }


        //--------------------------------------------------------------------
        self_type& premultiply()
        {
            if (a < base_mask)
            {
                if(a == 0) v = 0;
                else v = multiply(v, a);
            }
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& demultiply()
        {
            if (a < base_mask)
            {
                if (a == 0)
                {
                    v = 0;
                }
                else
                {
                    calc_type v_ = (calc_type(v) * base_mask) / a;
					v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_);
                }
            }
            return *this;
        }

        //--------------------------------------------------------------------
        self_type gradient(self_type c, double k) const
        {
            self_type ret;
            calc_type ik = uround(k * base_scale);
            ret.v = lerp(v, c.v, ik);
            ret.a = lerp(a, c.a, ik);
            return ret;
        }

        //--------------------------------------------------------------------
        AGG_INLINE void add(const self_type& c, unsigned cover)
        {
            calc_type cv, ca;
            if (cover == cover_mask)
            {
                if (c.a == base_mask) 
                {
                    *this = c;
                    return;
                }
                else
                {
                    cv = v + c.v; 
                    ca = a + c.a; 
                }
            }
            else
            {
                cv = v + mult_cover(c.v, cover);
                ca = a + mult_cover(c.a, cover);
            }
            v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv);
            a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca);
        }

        //--------------------------------------------------------------------
        static self_type no_color() { return self_type(0,0); }
    };


    //===================================================================gray32
    struct gray32
    {
        typedef float value_type;
        typedef double calc_type;
        typedef double long_type;
        typedef gray32 self_type;

        value_type v;
        value_type a;

        // Calculate grayscale value as per ITU-R BT.709.
        static value_type luminance(double r, double g, double b)
        {
            return value_type(0.2126 * r + 0.7152 * g + 0.0722 * b);
        }

        static value_type luminance(const rgba& c)
        {
            return luminance(c.r, c.g, c.b);
        }

        static value_type luminance(const rgba32& c)
        {
            return luminance(c.r, c.g, c.b);
        }

        static value_type luminance(const rgba8& c)
        {
            return luminance(c.r / 255.0, c.g / 255.0, c.g / 255.0);
        }

        static value_type luminance(const rgba16& c)
        {
            return luminance(c.r / 65535.0, c.g / 65535.0, c.g / 65535.0);
        }

        //--------------------------------------------------------------------
        gray32() {}

        //--------------------------------------------------------------------
        explicit gray32(value_type v_, value_type a_ = 1) :
            v(v_), a(a_) {}

        //--------------------------------------------------------------------
        gray32(const self_type& c, value_type a_) :
            v(c.v), a(a_) {}

        //--------------------------------------------------------------------
        gray32(const rgba& c) :
            v(luminance(c)),
            a(value_type(c.a)) {}

        //--------------------------------------------------------------------
        gray32(const rgba8& c) :
            v(luminance(c)),
            a(value_type(c.a / 255.0)) {}

        //--------------------------------------------------------------------
        gray32(const srgba8& c) :
            v(luminance(rgba32(c))),
            a(value_type(c.a / 255.0)) {}

        //--------------------------------------------------------------------
        gray32(const rgba16& c) :
            v(luminance(c)),
            a(value_type(c.a / 65535.0)) {}

        //--------------------------------------------------------------------
        gray32(const rgba32& c) :
            v(luminance(c)),
            a(value_type(c.a)) {}

        //--------------------------------------------------------------------
        gray32(const gray8& c) :
            v(value_type(c.v / 255.0)), 
            a(value_type(c.a / 255.0)) {}

        //--------------------------------------------------------------------
        gray32(const sgray8& c) :
            v(sRGB_conv<value_type>::rgb_from_sRGB(c.v)), 
            a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {}

        //--------------------------------------------------------------------
        gray32(const gray16& c) :
            v(value_type(c.v / 65535.0)), 
            a(value_type(c.a / 65535.0)) {}

        //--------------------------------------------------------------------
        operator rgba() const 
        {
            return rgba(v, v, v, a);
        }

        //--------------------------------------------------------------------
        operator gray8() const 
        {
            return gray8(uround(v * 255.0), uround(a * 255.0));
        }

        //--------------------------------------------------------------------
        operator sgray8() const 
        {
            // Return (non-premultiplied) sRGB values.
            return sgray8(
                sRGB_conv<value_type>::rgb_to_sRGB(v), 
                sRGB_conv<value_type>::alpha_to_sRGB(a));
        }

        //--------------------------------------------------------------------
        operator gray16() const 
        {
            return gray16(uround(v * 65535.0), uround(a * 65535.0));
        }

        //--------------------------------------------------------------------
        operator rgba8() const 
        {
            rgba8::value_type y = uround(v * 255.0);
            return rgba8(y, y, y, uround(a * 255.0));
        }

        //--------------------------------------------------------------------
        operator srgba8() const 
        {
            srgba8::value_type y = sRGB_conv<value_type>::rgb_to_sRGB(v);
            return srgba8(y, y, y, sRGB_conv<value_type>::alpha_to_sRGB(a));
        }

		//--------------------------------------------------------------------
		operator rgba16() const
		{
			rgba16::value_type y = uround(v * 65535.0);
			return rgba16(y, y, y, uround(a * 65535.0));
		}

		//--------------------------------------------------------------------
		operator rgba32() const
		{
            return rgba32(v, v, v, a);
		}

		//--------------------------------------------------------------------
        static AGG_INLINE double to_double(value_type a)
        {
            return a;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type from_double(double a)
        {
            return value_type(a);
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type empty_value()
        {
            return 0;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type full_value()
        {
            return 1;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_transparent() const
        {
            return a <= 0;
        }

        //--------------------------------------------------------------------
        AGG_INLINE bool is_opaque() const
        {
            return a >= 1;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type invert(value_type x) 
        {
            return 1 - x;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type multiply(value_type a, value_type b) 
        {
            return value_type(a * b);
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type demultiply(value_type a, value_type b) 
        {
            return (b == 0) ? 0 : value_type(a / b);
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downscale(T a) 
        {
            return a;
        }

        //--------------------------------------------------------------------
        template<typename T>
        static AGG_INLINE T downshift(T a, unsigned n) 
        {
            return n > 0 ? a / (1 << n) : a;
        }

        //--------------------------------------------------------------------
        static AGG_INLINE value_type mult_cover(value_type a, cover_type b) 
        {
            return value_type(a * b / cover_mask);
        }

        //--------------------------------------------------------------------
        static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) 
        {
            return cover_type(uround(a * b));
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a, assuming q is premultiplied by a.
        static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) 
        {
            return (1 - a) * p + q; // more accurate than "p + q - p * a"
        }
        
        //--------------------------------------------------------------------
        // Interpolate p to q by a.
        static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) 
        {
			// The form "p + a * (q - p)" avoids a multiplication, but may produce an 
			// inaccurate result. For example, "p + (q - p)" may not be exactly equal 
			// to q. Therefore, stick to the basic expression, which at least produces 
			// the correct result at either extreme.
			return (1 - a) * p + a * q;
        }
        
        //--------------------------------------------------------------------
        self_type& clear()
        {
            v = a = 0;
			return *this;
        }

        //--------------------------------------------------------------------
        self_type& transparent()
        {
            a = 0;
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& opacity(double a_)
        {
            if (a_ < 0) a = 0;
            else if (a_ > 1) a = 1;
            else a = value_type(a_);
			return *this;
        }

        //--------------------------------------------------------------------
        double opacity() const
        {
            return a;
        }


        //--------------------------------------------------------------------
        self_type& premultiply()
        {
            if (a < 0) v = 0;
            else if(a < 1) v *= a;
            return *this;
        }

        //--------------------------------------------------------------------
        self_type& demultiply()
        {
            if (a < 0) v = 0;
            else if (a < 1) v /= a;
            return *this;
        }

        //--------------------------------------------------------------------
        self_type gradient(self_type c, double k) const
        {
            return self_type(
                value_type(v + (c.v - v) * k), 
                value_type(a + (c.a - a) * k));
        }

        //--------------------------------------------------------------------
        static self_type no_color() { return self_type(0,0); }
    };
}




#endif
