/*========================================================================
    colors.h : Color definitions for CMVision2 and the Simple Image class
  ------------------------------------------------------------------------
    Copyright (C) 1999-2002  James R. Bruce
    School of Computer Science, Carnegie Mellon University
  ------------------------------------------------------------------------
    This software is distributed under the GNU General Public License,
    version 2.  If you do not have a copy of this licence, visit
    www.gnu.org, or write: Free Software Foundation, 59 Temple Place,
    Suite 330 Boston, MA 02111-1307 USA.  This program is distributed
    in the hope that it will be useful, but WITHOUT ANY WARRANTY,
    including MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  ========================================================================*/

#ifndef __COLORS_H__
#define __COLORS_H__

#define RGB_COLOR_NAMES
#define RGB_OPERATORS


//==== Color Classes =================================================//

typedef unsigned char uchar;
typedef unsigned long ulong;

template<class elem>
struct yuv_generic{
  elem y,u,v;

  yuv_generic()
    {}
  yuv_generic(elem ny,elem nu,elem nv)
    {y=ny; u=nu; v=nv;}

  void set(elem _y,elem _u,elem _v);

  yuv_generic<elem> &operator+=(const yuv_generic<elem> p);
  yuv_generic<elem> &operator-=(const yuv_generic<elem> p);
  yuv_generic<elem> &operator*=(const yuv_generic<elem> p);
  yuv_generic<elem> &operator/=(const yuv_generic<elem> p);

  yuv_generic<elem> operator+(const yuv_generic<elem> p) const;
  yuv_generic<elem> operator-(const yuv_generic<elem> p) const;
  yuv_generic<elem> operator*(const yuv_generic<elem> p) const;
  yuv_generic<elem> operator/(const yuv_generic<elem> p) const;

  yuv_generic<elem> operator*(elem f) const;
  yuv_generic<elem> operator/(elem f) const;
  yuv_generic<elem> &operator*=(elem f);
  yuv_generic<elem> &operator/=(elem f);

  bool operator==(const yuv_generic<elem> p) const;
  bool operator!=(const yuv_generic<elem> p) const;
  bool operator< (const yuv_generic<elem> p) const;
  bool operator> (const yuv_generic<elem> p) const;
  bool operator<=(const yuv_generic<elem> p) const;
  bool operator>=(const yuv_generic<elem> p) const;
};

#define YUVCOMP(p) (p).y,(p).u,(p).v

template<class elem>
void yuv_generic<elem>::set(elem _y,elem _u,elem _v)
{
  y = _y;
  u = _u;
  v = _v;
}

#define YUV_GENERIC_EQUAL_BINARY_OPERATOR(opr) \
  template <class elem> \
  yuv_generic<elem> &yuv_generic<elem>::operator opr (const yuv_generic<elem> p) \
  {                  \
    y = y opr p.y;   \
    u = u opr p.u;   \
    v = v opr p.v;   \
    return(*this);   \
  }

YUV_GENERIC_EQUAL_BINARY_OPERATOR(+=)
YUV_GENERIC_EQUAL_BINARY_OPERATOR(-=)
YUV_GENERIC_EQUAL_BINARY_OPERATOR(*=)
YUV_GENERIC_EQUAL_BINARY_OPERATOR(/=)

#define YUV_GENERIC_BINARY_OPERATOR(opr) \
  template <class elem> \
  yuv_generic<elem> yuv_generic<elem>::operator opr (const yuv_generic<elem> p) const \
  {                  \
    yuv_generic<elem> r; \
    r.y = y opr p.y; \
    r.u = u opr p.u; \
    r.v = v opr p.v; \
    return(r);       \
  }

YUV_GENERIC_BINARY_OPERATOR(+)
YUV_GENERIC_BINARY_OPERATOR(-)
YUV_GENERIC_BINARY_OPERATOR(*)
YUV_GENERIC_BINARY_OPERATOR(/)

#define YUV_GENERIC_SCALAR_OPERATOR(opr) \
  template <class elem> \
  yuv_generic<elem> yuv_generic<elem>::operator opr (const elem f) const \
  {                  \
    yuv_generic<elem> r; \
    r.y = y opr f;   \
    r.u = u opr f;   \
    r.v = v opr f;   \
    return(r);       \
  }

YUV_GENERIC_SCALAR_OPERATOR(*)
YUV_GENERIC_SCALAR_OPERATOR(/)

#define YUV_GENERIC_EQUAL_SCALAR_OPERATOR(opr) \
  template <class elem> \
  yuv_generic<elem> &yuv_generic<elem>::operator opr (elem f) \
  {                \
    y = y opr f;   \
    u = u opr f;   \
    v = v opr f;   \
    return(*this); \
  }

YUV_GENERIC_EQUAL_SCALAR_OPERATOR(*=)
YUV_GENERIC_EQUAL_SCALAR_OPERATOR(/=)

#define YUV_GENERIC_LOGIC_OPERATOR(opr,combine) \
  template <class elem> \
  bool yuv_generic<elem>::operator opr (const yuv_generic<elem> p) const \
  {                            \
    return((y opr p.y) combine \
           (u opr p.u) combine \
           (v opr p.v));       \
  }

YUV_GENERIC_LOGIC_OPERATOR(==,&&)
YUV_GENERIC_LOGIC_OPERATOR(!=,||)

YUV_GENERIC_LOGIC_OPERATOR(< ,&&)
YUV_GENERIC_LOGIC_OPERATOR(> ,&&)
YUV_GENERIC_LOGIC_OPERATOR(<=,&&)
YUV_GENERIC_LOGIC_OPERATOR(>=,&&)

#ifndef YUVF_STRUCT
#define YUVF_STRUCT
typedef yuv_generic<float> yuvf;
#endif

#ifndef YUV_STRUCT
#define YUV_STRUCT
typedef yuv_generic<uchar> yuv;
#endif

#ifndef YUVI_STRUCT
#define YUVI_STRUCT
typedef yuv_generic<int> yuvi;
#endif

#ifndef YUYV_STRUCT
#define YUYV_STRUCT
struct yuyv{
  uchar y1,u,y2,v;
};
#endif

struct uyvy{
#ifndef UYVY_STRUCT
#define UYVY_STRUCT
  uchar u,y1,v,y2;
};
#endif

#ifndef RGB_STRUCT
#define RGB_STRUCT
struct rgb{
  uchar red,green,blue;
  bool operator ==(const rgb &x) const {
    return (red  ==x.red   &&
            green==x.green &&
            blue ==x.blue);
  }
  bool operator !=(const rgb &x) const {
    return !operator==(x);
  }

  void set(uchar r,uchar g,uchar b)
    {red=r; green=g; blue=b;}
  void set(uchar y)
    {red = green = blue = y;}
};
#endif

#ifndef RGB_INT_STRUCT
#define RGB_INT_STRUCT
struct rgb_int{
  int r,g,b;

  void set(int _r,int _g,int _b)
    {r=_r; g=_g; b=_b;}
};
#endif

#ifndef RGBA_STRUCT
#define RGBA_STRUCT
struct rgba{
  uchar r,g,b,a;

  void set(uchar _r,uchar _g,uchar _b,uchar _a)
    {r=_r; g=_g; b=_b; a=_a;}
};
#endif

#ifndef RGBA_INT_STRUCT
#define RGBA_INT_STRUCT
struct rgba_int{
  int r,g,b,a;

  void set(int _r,int _g,int _b,int _a)
    {r=_r; g=_g; b=_b; a=_a;}
};
#endif

#ifndef ARGB_STRUCT
#define ARGB_STRUCT
struct argb{
  uchar a,r,g,b;

  void set(uchar _r,uchar _g,uchar _b,uchar _a)
    {r=_r; g=_g; b=_b; a=_a;}
};
#endif

#ifndef RGBF_STRUCT
#define RGBF_STRUCT
struct rgbf{
  float red,green,blue;

  rgbf()
    {}
  rgbf(float nred,float ngreen,float nblue)
    {red=nred; green=ngreen; blue=nblue;}
};
#endif

#ifndef RGBAF_STRUCT
#define RGBAF_STRUCT
struct rgbaf{
  float r,g,b,a;
};
#endif

#ifndef ARGBF_STRUCT
#define ARGBF_STRUCT
struct argbf{
  float a,r,g,b;
};
#endif


//==== Color Names ===================================================//

#ifdef RGB_COLOR_NAMES
namespace Rgb{
  const rgb Black     = {  0,  0,  0};
  const rgb Blue      = {  0,  0,255};
  const rgb Green     = {  0,255,  0};
  const rgb Red       = {255,  0,  0};
  const rgb White     = {255,255,255};
  const rgb Gray      = {128,128,128};
  const rgb DarkGreen = {  0,128,  0};
  const rgb DarkGray  = { 32, 32, 48};
};
#endif


//==== Color Arithmetic ==============================================//

#ifdef RGB_OPERATORS
rgb to_rgb(rgbf c);
rgbf to_rgbf(rgb c);
rgbf clip(rgbf c);
rgbf operator +(const rgbf a,const rgbf b);
rgbf operator *(const rgbf a,const rgbf b);
rgbf operator *(const rgbf a,const double m);
rgbf pow(const rgbf x,const double p);
double sse(rgbf a,rgbf b);
#endif

#endif
