    //------------------------------------------------------------------------------
    // emColor.h
    //
    // Copyright (C) 2001,2003-2008,2010,2014 Oliver Hamann.
    //
    // Homepage: http://eaglemode.sourceforge.net/
    //
    // This program is free software: you can redistribute it and/or modify it under
    // the terms of the GNU General Public License version 3 as published by the
    // Free Software Foundation.
    //
    // This program is distributed in the hope that it will be useful, but WITHOUT
    // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
    // more details.
    //
    // You should have received a copy of the GNU General Public License version 3
    // along with this program. If not, see <http://www.gnu.org/licenses/>.
    //------------------------------------------------------------------------------

    #ifndef emColor_h
    #define emColor_h

    #ifndef emStd2_h
    #include <emCore/emStd2.h>
    #endif

    //==============================================================================
    //================================== emColor ===================================
    //==============================================================================

    class emColor {

    public:

            // Class for a 32-bit color value. A color has four components, each of
            // eight bits: red, green, blue and alpha. An alpha value of 255 means
            // opaque, 0 means totally transparent. A here so called "packed color"
            // is a 32-bit unsigned integer with:
            //   Bits 0-7  : Alpha component
            //   Bits 8-15 : Blue component
            //   Bits 16-23: Green component
            //   Bits 24-31: Red component

            enum {
                    // Some predefined packed colors.
                    BLACK  =0x000000ff,
                    WHITE  =0xffffffff,
                    RED    =0xff0000ff,
                    GREEN  =0x00ff00ff,
                    BLUE   =0x0000ffff,
                    YELLOW =0xffff00ff,
                    CYAN   =0x00ffffff,
                    MAGENTA=0xff00ffff
            };

            emColor();
                    // Performs no initialization! (emColor is a primitive type)

            emColor(emUInt32 packed);
                    // Construct from a packed color.

            emColor(emByte red, emByte green, emByte blue, emByte alpha=255);
                    // Construct from color components.

            emColor(const emColor & color);
                    // Construct by copying a color.

            emColor(const emColor & rgb, emByte alpha);
                    // Construct by copying a color, but override the alpha
                    // component.

            void TryParse(const char * str) throw(emException);
                    // Try to set this color by interpreting the given string as a
                    // color. Throw an error message on failure. Currently, this
                    // tries to interpret only X11 color strings like "#f8a91c" or
                    // "Powder Blue". Future extension may even accept additional
                    // formats.

            emColor & operator = (const emColor & color);
            emColor & operator = (emUInt32 packed);
                    // Copy a color or a packed color.

            operator emUInt32 () const;
            emUInt32 Get() const;
                    // Convert this color to a packed color.

            void Set(emUInt32 packed);
            void Set(emByte red, emByte green, emByte blue, emByte alpha=255);
            void Set(const emColor & color);
            void Set(const emColor & rgb, emByte alpha);
                    // Like the constructors.

            emByte GetRed() const;
            emByte GetGreen() const;
            emByte GetBlue() const;
            emByte GetAlpha() const;
            void SetRed(emByte red);
            void SetGreen(emByte green);
            void SetBlue(emByte blue);
            void SetAlpha(emByte alpha);
                    // Get or set individual components.

            bool IsTotallyTransparent() const;
                    // Ask whether the alpha component is 0.

            bool IsOpaque() const;
                    // Ask whether the alpha component is 255.

            bool IsGrey() const;
                    // Ask whether the red, green and blue components are equal.

            emByte GetGrey() const;
            void SetGrey(emByte grey, emByte alpha=255);
                    // Get or set in grey format.

            float GetHue() const;
            float GetSat() const;
            float GetVal() const;
            void SetHue(float hue);
            void SetSat(float sat);
            void SetVal(float val);
            void SetHSVA(float hue, float sat, float val, emByte alpha=255);
                    // Get or set in Hue-Saturation-Value format. Hue is in degrees
                    // (0.0-360.0). Sat and val are in percent (0.0-100.0).

            emColor GetBlended(const emColor & color, float weight) const;
                    // Return a blending of this color and a given color. The given
                    // weight of the given color is in percent.

            emColor GetLighted(float light) const;
                    // Get a shaded or lighted version of this color. The light
                    // parameter ranges from -100.0 to 100.0. -100.0 means black
                    // (fully shaded), 0.0 means no change, 100.0 means white (fully
                    // highlighted).

            emColor GetTransparented(float tp) const;
                    // Get a more opaque or transparent version of this color. The
                    // argument tp ranges from -100.0 to 100.0. -100.0 means fully
                    // opaque, 0.0 means no change, 100.0 means fully transparent.

            bool operator == (const emColor & color) const;
            bool operator != (const emColor & color) const;
            bool operator == (emUInt32 packed) const;
            bool operator != (emUInt32 packed) const;
            friend bool operator == (emUInt32 packed, const emColor & color);
            friend bool operator != (emUInt32 packed, const emColor & color);
                    // Compare colors.

    private:
            union {
                    emUInt32 Packed;
                    struct {
    #                       if EM_BYTE_ORDER==4321
                                    emByte Red, Green, Blue, Alpha;
    #                       elif EM_BYTE_ORDER==1234
                                    emByte Alpha, Blue, Green, Red;
    #                       elif EM_BYTE_ORDER==3412
                                    emByte Green, Red, Alpha, Blue;
    #                       else
    #                               error unexpected value for EM_BYTE_ORDER
    #                       endif
                    } Components;
            };
    };

    inline emColor::emColor()
    {
    }

    inline emColor::emColor(emUInt32 packed)
    {
            Packed=packed;
    }

    inline emColor::emColor(emByte red, emByte green, emByte blue, emByte alpha)
    {
            Components.Red=red;
            Components.Green=green;
            Components.Blue=blue;
            Components.Alpha=alpha;
    }

    inline emColor::emColor(const emColor & color)
    {
            Packed=color.Packed;
    }

    inline emColor::emColor(const emColor & rgb, emByte alpha)
    {
            // Did not work error-free with every compiler:
            //  Packed=rgb.Packed;
            //  Components.Alpha=alpha;
            // Therefore:
            Components.Red=rgb.Components.Red;
            Components.Green=rgb.Components.Green;
            Components.Blue=rgb.Components.Blue;
            Components.Alpha=alpha;
    }

    inline emColor & emColor::operator = (const emColor & color)
    {
            Packed=color.Packed;
            return *this;
    }

    inline emColor & emColor::operator = (emUInt32 packed)
    {
            Packed=packed;
            return *this;
    }

    inline emColor::operator emUInt32 () const
    {
            return Packed;
    }

    inline emUInt32 emColor::Get() const
    {
            return Packed;
    }

    inline void emColor::Set(emUInt32 packed)
    {
            Packed=packed;
    }

    inline void emColor::Set(emByte red, emByte green, emByte blue, emByte alpha)
    {
            Components.Red=red;
            Components.Green=green;
            Components.Blue=blue;
            Components.Alpha=alpha;
    }

    inline void emColor::Set(const emColor & color)
    {
            Packed=color.Packed;
    }

    inline void emColor::Set(const emColor & rgb, emByte alpha)
    {
            // Did not work error-free with every compiler:
            //  Packed=rgb.Packed;
            //  Components.Alpha=alpha;
            // Therefore:
            Components.Red=rgb.Components.Red;
            Components.Green=rgb.Components.Green;
            Components.Blue=rgb.Components.Blue;
            Components.Alpha=alpha;
    }

    inline emByte emColor::GetRed() const
    {
            return Components.Red;
    }

    inline emByte emColor::GetGreen() const
    {
            return Components.Green;
    }

    inline emByte emColor::GetBlue() const
    {
            return Components.Blue;
    }

    inline emByte emColor::GetAlpha() const
    {
            return Components.Alpha;
    }

    inline void emColor::SetRed(emByte red)
    {
            Components.Red=red;
    }

    inline void emColor::SetGreen(emByte green)
    {
            Components.Green=green;
    }

    inline void emColor::SetBlue(emByte blue)
    {
            Components.Blue=blue;
    }

    inline void emColor::SetAlpha(emByte alpha)
    {
            Components.Alpha=alpha;
    }

    inline bool emColor::IsTotallyTransparent() const
    {
            return Components.Alpha==0;
    }

    inline bool emColor::IsOpaque() const
    {
            return Components.Alpha==255;
    }

    inline bool emColor::IsGrey() const
    {
            return
                    Components.Red==Components.Green &&
                    Components.Red==Components.Blue
            ;
    }

    inline emByte emColor::GetGrey() const
    {
            return (emByte)(
                    (
                            ((int)Components.Red)+
                            ((int)Components.Green)+
                            ((int)Components.Blue)+
                            1
                    )/3
            );
    }

    inline void emColor::SetGrey(emByte grey, emByte alpha)
    {
            Components.Red=grey;
            Components.Green=grey;
            Components.Blue=grey;
            Components.Alpha=alpha;
    }

    inline void emColor::SetHue(float hue)
    {
            SetHSVA(hue,GetSat(),GetVal(),GetAlpha());
    }

    inline void emColor::SetSat(float sat)
    {
            SetHSVA(GetHue(),sat,GetVal(),GetAlpha());
    }

    inline void emColor::SetVal(float val)
    {
            SetHSVA(GetHue(),GetSat(),val,GetAlpha());
    }

    inline bool emColor::operator == (const emColor & color) const
    {
            return Packed==color.Packed;
    }

    inline bool emColor::operator != (const emColor & color) const
    {
            return Packed!=color.Packed;
    }

    inline bool emColor::operator == (emUInt32 packed) const
    {
            return Packed==packed;
    }

    inline bool emColor::operator != (emUInt32 packed) const
    {
            return Packed!=packed;
    }

    inline bool operator == (emUInt32 packed, const emColor & color)
    {
            return packed==color.Packed;
    }

    inline bool operator != (emUInt32 packed, const emColor & color)
    {
            return packed!=color.Packed;
    }

    #endif