#ifndef OPENGLTEMPLATED
#define OPENGLTEMPLATED

/**
This file was written primarily to write OpenGL code that
 can be templated, rather than writing specific endless 
 versions of code that caters for the diffent types.

More OpenGL commands will be added as the need arises.
*/

#include <GL/gl.h>

#include <cassert>


/** Automate class specialization for two arguments and
 known argument signature. */
#define CLASSFUNC2xy(cnm,typ,fnname) \
template<> \
class cnm<typ> \
{ \
public: \
  void operator ()  \
  ( \
    typ const x,  \
    typ const y  \
  ) const           \
    { fnname(x,y); } \
  template< typename U> \
  void operator () (U const & pt) \
    { fnname(pt.x,pt.y); } \
}

/** Automate class specialization for three arguments and
 known argument signature. */
#define CLASSFUNC3xyz(cnm,typ,fnname) \
template<> \
class cnm<typ> \
{ \
public: \
  void operator ()  \
  ( \
    typ const x,  \
    typ const y,  \
    typ const z   \
  ) const           \
    { fnname(x,y,z); } \
  template< typename U> \
  void operator () (U const & pt) \
    { fnname(pt.x,pt.y,pt.z); } \
}

/** Automate class specialization for four arguments and
 known argument signature. */
#define CLASSFUNC4xyzw(cnm,typ,fnname) \
template<> \
class cnm<typ> \
{ \
public: \
  void operator ()  \
  ( \
    typ const x,  \
    typ const y,  \
    typ const z,  \
    typ const w   \
  ) const           \
    { fnname(x,y,z,w); } \
}

/** Automate class specialization for one argument and
 known argument signature. */
#define CLASSFUNC1v(cnm,typ,fnname) \
template<> \
class cnm<typ> \
{ \
public: \
  void operator() (typ const *v ) const \
    { fnname(v); } \
}






/*!
\brief The OpenGL command glTranslate{d,f} has had its type templated
  using class specialization.
*/
template< typename T >
class glTranslateT
{
public:
 
  /** Multiply the current matrix by a translation matrix. */ 
  void operator () (T const x, T const y) const
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex2{d,f,i,s} has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex2T
{
public:
 
  /** Call the OpenGL function. */ 
  void operator () (T const x, T const y) const
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex3{d,f,i,s} has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex3T
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () (T const x, T const y, T const z) const
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex4{d,f,i,s} has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex4T
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () 
  (
    T const x, 
    T const y, 
    T const z, 
    T const w
  ) const
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex2{d,f,i,s}v has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex2Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex3{d,f,i,s}v has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex3Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};

/*!
\brief The OpenGL command glVertex4{d,f,i,s}v has had its type 
  templated using class specialization.
*/
template< typename T >
class glVertex4Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};

/*!
\brief The OpenGL command glNormal3{b,d,f,i,s} has had its type 
  templated using class specialization.
*/
template< typename T >
class glNormal3T
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () (T const x, T const y, T const z) const
    { assert(false); }
};

/*!
\brief The OpenGL command glNormal3{b,d,f,i,s}v has had its type 
  templated using class specialization.
*/
template< typename T >
class glNormal3Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};

/*!
\brief The OpenGL command glColor3{b,d,f,i,s,ub,ui,us} has had 
  its type templated using class specialization.
*/
template< typename T >
class glColor3T
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () 
  (
    T const x, 
    T const y, 
    T const z 
  ) const
    { assert(false); }
};

/*!
\brief The OpenGL command glColor3{b,d,f,i,s,ub,ui,us}v has had 
  its type templated using class specialization.
*/
template< typename T >
class glColor3Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};

/*!
\brief The OpenGL command glColor4{b,d,f,i,s,ub,ui,us} has had 
  its type templated using class specialization.
*/
template< typename T >
class glColor4T
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () 
  (
    T const x, 
    T const y, 
    T const z, 
    T const w
  ) const
    { assert(false); }
};

/*!
\brief The OpenGL command glColor4{b,d,f,i,s,ub,ui,us}v has had 
  its type templated using class specialization.
*/
template< typename T >
class glColor4Tv
{
public:
  
  /** Call the OpenGL function. */ 
  void operator () ( T const *v ) const 
    { assert(false); }
};






//******************************************************
//  Implementation


CLASSFUNC3xyz(glTranslateT,GLdouble,glTranslated);
CLASSFUNC3xyz(glTranslateT,GLfloat,glTranslatef);

CLASSFUNC2xy(glVertex2T,GLdouble,glVertex2d);
CLASSFUNC2xy(glVertex2T,GLfloat,glVertex2f);
CLASSFUNC2xy(glVertex2T,GLint,glVertex2i);
CLASSFUNC2xy(glVertex2T,GLshort,glVertex2s);

CLASSFUNC3xyz(glVertex3T,GLdouble,glVertex3d);
CLASSFUNC3xyz(glVertex3T,GLfloat,glVertex3f);
CLASSFUNC3xyz(glVertex3T,GLint,glVertex3i);
CLASSFUNC3xyz(glVertex3T,GLshort,glVertex3s);

CLASSFUNC4xyzw(glVertex4T,GLdouble,glVertex4d);
CLASSFUNC4xyzw(glVertex4T,GLfloat,glVertex4f);
CLASSFUNC4xyzw(glVertex4T,GLint,glVertex4i);
CLASSFUNC4xyzw(glVertex4T,GLshort,glVertex4s);

CLASSFUNC1v(glVertex2Tv,GLdouble,glVertex2dv);
CLASSFUNC1v(glVertex2Tv,GLfloat,glVertex2fv);
CLASSFUNC1v(glVertex2Tv,GLint,glVertex2iv);
CLASSFUNC1v(glVertex2Tv,GLshort,glVertex2sv);

CLASSFUNC1v(glVertex3Tv,GLdouble,glVertex3dv);
CLASSFUNC1v(glVertex3Tv,GLfloat,glVertex3fv);
CLASSFUNC1v(glVertex3Tv,GLint,glVertex3iv);
CLASSFUNC1v(glVertex3Tv,GLshort,glVertex3sv);

CLASSFUNC1v(glVertex4Tv,GLdouble,glVertex4dv);
CLASSFUNC1v(glVertex4Tv,GLfloat,glVertex4fv);
CLASSFUNC1v(glVertex4Tv,GLint,glVertex4iv);
CLASSFUNC1v(glVertex4Tv,GLshort,glVertex4sv);

CLASSFUNC3xyz(glNormal3T,GLbyte,glNormal3b);
CLASSFUNC3xyz(glNormal3T,GLdouble,glNormal3d);
CLASSFUNC3xyz(glNormal3T,GLfloat,glNormal3f);
CLASSFUNC3xyz(glNormal3T,GLint,glNormal3i);
CLASSFUNC3xyz(glNormal3T,GLshort,glNormal3s);

CLASSFUNC1v(glNormal3Tv,GLbyte,glNormal3bv);
CLASSFUNC1v(glNormal3Tv,GLdouble,glNormal3dv);
CLASSFUNC1v(glNormal3Tv,GLfloat,glNormal3fv);
CLASSFUNC1v(glNormal3Tv,GLint,glNormal3iv);
CLASSFUNC1v(glNormal3Tv,GLshort,glNormal3sv);

CLASSFUNC3xyz(glColor3T,GLbyte,glColor3b);
CLASSFUNC3xyz(glColor3T,GLdouble,glColor3d);
CLASSFUNC3xyz(glColor3T,GLfloat,glColor3f);
CLASSFUNC3xyz(glColor3T,GLint,glColor3i);
CLASSFUNC3xyz(glColor3T,GLshort,glColor3s);
CLASSFUNC3xyz(glColor3T,GLubyte,glColor3ub);
CLASSFUNC3xyz(glColor3T,GLuint,glColor3ui);
CLASSFUNC3xyz(glColor3T,GLushort,glColor3us);

CLASSFUNC1v(glColor3Tv,GLbyte,glColor3bv);
CLASSFUNC1v(glColor3Tv,GLdouble,glColor3dv);
CLASSFUNC1v(glColor3Tv,GLfloat,glColor3fv);
CLASSFUNC1v(glColor3Tv,GLint,glColor3iv);
CLASSFUNC1v(glColor3Tv,GLshort,glColor3sv);
CLASSFUNC1v(glColor3Tv,GLubyte,glColor3ubv);
CLASSFUNC1v(glColor3Tv,GLuint,glColor3uiv);
CLASSFUNC1v(glColor3Tv,GLushort,glColor3usv);

CLASSFUNC4xyzw(glColor4T,GLbyte,glColor4b);
CLASSFUNC4xyzw(glColor4T,GLdouble,glColor4d);
CLASSFUNC4xyzw(glColor4T,GLfloat,glColor4f);
CLASSFUNC4xyzw(glColor4T,GLint,glColor4i);
CLASSFUNC4xyzw(glColor4T,GLshort,glColor4s);
CLASSFUNC4xyzw(glColor4T,GLubyte,glColor4ub);
CLASSFUNC4xyzw(glColor4T,GLuint,glColor4ui);
CLASSFUNC4xyzw(glColor4T,GLushort,glColor4us);

CLASSFUNC1v(glColor4Tv,GLbyte,glColor4bv);
CLASSFUNC1v(glColor4Tv,GLdouble,glColor4dv);
CLASSFUNC1v(glColor4Tv,GLfloat,glColor4fv);
CLASSFUNC1v(glColor4Tv,GLint,glColor4iv);
CLASSFUNC1v(glColor4Tv,GLshort,glColor4sv);
CLASSFUNC1v(glColor4Tv,GLubyte,glColor4ubv);
CLASSFUNC1v(glColor4Tv,GLuint,glColor4uiv);
CLASSFUNC1v(glColor4Tv,GLushort,glColor4usv);


#undef CLASSFUNC1v
#undef CLASSFUNC2xy
#undef CLASSFUNC3xyz
#undef CLASSFUNC4xyzw

#endif



