#ifndef GOBJ_H
#define GOBJ_H


#include <gobjbase.h>


/*
Brief : wrap OpenGL calls in objects for an OO graphics library. 

  Intro
  -----

  This technique converts a modular/procedual API 
  into an object oriented API by wrapping the OpenGL calls 
  in objects.  The input to the function become members of 
  that object. Returned data are pointer references.

  This is an extension to OpenGL in the sense that if OpenGL 
  changes the changes are mirrored in the OpenGL objects.  
  So programmers familiar with OpenGL will 
  understand because essentially you write out OpenGL.

  By using a stack(see gobjContainer) you can insert 
  objects and execute the code at a later date.  So what are 
  normally function calls to OpenGL are instead objects 
  pushed to the end of a stack.  By executing the stack 
  from start to end is equivalent to the hard coded calling 
  of the OpenGL functions in the same order.

  Since this stack can be compiled to a display list it
  can generally be made efficient.

  The other way is deriving from gobj and writing OpenGL 
  code in draw() which is generally how graphics is written.  

  So the scene is really a stack or vector of gobj's. gobj 
  is the base graphics class.

  This library is primitive - gobj does not have a copy 
  constructor for memory management.  Instead a call back
  is used - see graphicsImmediateDeferred.h . This is
  the hardest part of the library to come to grips with,
  because we intuitively would build a stack, then move
  the code accross when we need it, but without deep copy
  you need to write a callback function which pushes the 
  code when its called - hence creating the copy then.
  

  Performance
  -----------
  Whenever I encountered a graphics problem with this there 
  is always some technique to make it work out.  Performance 
  is not an issue because it can be addressed. 
  
  graphicsImmediateDeferred.h was designed for graphics
  processing which changes infrequently 

  How to use this library
  -----------------------
  Become familiar with gobj and gobjContainer.

  By pushing gobjContainers into the global gobjContainer
  stack and having a pointer to them simply delete their
  contents and draw the new updated state when convenient.

  Then you can use other techniques such as indexing into
  the vector to remember positions, saving pointers pointing
  into the stack,...
*/


class gobjglColor3f : public gobj
{
public:


  /** The x coordinate. */
  float x;
  /** The y coordinate. */
  float y;
  /** The z coordinate. */
  float z;

  gobjglColor3f
  (
    floatc x_,
    floatc y_,
    floatc z_
  )
    : x(x_), y(y_), z(z_) {}
  /** Construct from string. */      
  gobjglColor3f(stringc & arg);
  /** Construct from string. */      
  boolc serializeInverse(stringc & arg); 

/*
  template< typename T >
  gobjglColor3f(T const & pt)
    : x(pt.x), y(pt.y), z(pt.z) {}
*/

  void draw()
    { GOBJDEBUGCODE glColor3f(x,y,z); }
};


class gobjglColor3d : public gobj
{
public:

  /** The x coordinate. */
  GLdouble x;
  /** The y coordinate. */
  GLdouble y;
  /** The z coordinate. */
  GLdouble z;

  gobjglColor3d()
    : x(0), y(0), z(0) {}

  gobjglColor3d
  (
    GLdouble x_,
    GLdouble y_,
    GLdouble z_
  )
    : x(x_), y(y_), z(z_) {}

  template< typename T >
  gobjglColor3d(T const & pt)
    : x(pt.x), y(pt.y), z(pt.z) {}

  void draw()
    { GOBJDEBUGCODE glColor3d(x,y,z); }
};


class gobjglColor4f : public gobj
{
public:

  float x;
  float y;
  float z;
  float a;

  gobjglColor4f
  (
    floatc x_,
    floatc y_,
    floatc z_,
    floatc a_
  )
    : x(x_), y(y_), z(z_), a(a_) {}

  void draw()
    { GOBJDEBUGCODE glColor4f(x,y,z,a); }
};


class gobjglColor4d : public gobj
{
public:

  typedef GLdouble W;

  W x;
  W y;
  W z;
  W a;

  gobjglColor4d
  (
    W const x_,
    W const y_,
    W const z_,
    W const a_
  )
    : x(x_), y(y_), z(z_), a(a_) {}

  void set( W const x_, W const y_, W const z_, W const a_)
    { x=x_; y=y_; z=z_; a=a_; }

  void draw()
    { GOBJDEBUGCODE glColor4d(x,y,z,a); }
};

// <TODO> Compiler seems to be experiencing unusual behaviour.
//  This code is failing.
//   targetcolor = new gobjglColor3ub(0,255,0);
//   targetcolor->x = 34;
//   cout << SHOW(targetcolor->x) << endl;
class gobjglColor3ub : public gobj, public point3<GLubyte>
{
public:

  typedef GLubyte W;

  gobjglColor3ub( W const x_, W const y_, W const z_ )
    : point3<W>(x_,y_,z_) {}

  void set( W const x_, W const y_, W const z_)
    { x=x_; y=y_; z=z_; }

  void draw()
    { GOBJDEBUGCODE glColor3ub(x,y,z); }
};

class gobjglColor4ub : public gobj
{
public:

  typedef GLubyte W;

  W x;
  W y;
  W z;
  W a;

  gobjglColor4ub
  (
    W const x_,
    W const y_,
    W const z_,
    W const a_
  )
    : x(x_), y(y_), z(z_), a(a_) {}

  void set( W const x_, W const y_, W const z_, W const a_)
    { x=x_; y=y_; z=z_; a=a_; }

  void draw()
    { GOBJDEBUGCODE glColor4ub(x,y,z,a); }
};


class gobjglRasterPos2f : public gobj
{
public:

  float x, y;

  gobjglRasterPos2f(floatc x_, floatc y_)
    : x(x_), y(y_) {}
  gobjglRasterPos2f(point2<float> const & p)
    : x(p.x), y(p.y) {}

  void draw()
    { GOBJDEBUGCODE glRasterPos2f(x,y); }

};

class gobjglRasterPos2i : public gobj
{
public:

  GLint x, y;

  gobjglRasterPos2i(GLint const x_, GLint const y_)
    : x(x_), y(y_) {}
  gobjglRasterPos2i(point2<GLint> const & p)
    : x(p.x), y(p.y) {}

  void draw()
    { GOBJDEBUGCODE glRasterPos2i(x,y); }

};

class gobjglRasterPos3f : public gobj
{
public:

  /** The x coordinate. */
  float x;
  /** The y coordinate. */
  float y; 
  /** The z coordinate. */
  float z;

  gobjglRasterPos3f
  (
    floatc x_, 
    floatc y_,
    floatc z_
  )
    : x(x_), y(y_), z(z_) {}
  gobjglRasterPos3f(point3<float> const & p)
    : x(p.x), y(p.y), z(p.z) {}

  void draw()
    { GOBJDEBUGCODE glRasterPos3f(x,y,z); }

};

class gobjglBegin : public gobj
{
public:
 
  GLenum mode;

  gobjglBegin(GLenum mode_)
    : mode(mode_) {}
  /** Construct from string. */  
  gobjglBegin(stringc & arg);
  /** Construct from string. */  
  boolc serializeInverse(stringc & arg);

  void draw()
    { GOBJDEBUGCODE glBegin(mode); }
};

class gobjglEnd : public gobj
{
public:
  void draw()
    { GOBJDEBUGCODE glEnd(); }
};

class gobjglVertex2f : public gobj
{
public:

  /** The x coordinate. */
  float x;

  /** The y coordinate. */
  float y;

  gobjglVertex2f
  (
    floatc x_, 
    floatc y_
  )
    : x(x_), y(y_) {}

  gobjglVertex2f
  (
    point2<float> const x
  )
    : x(x.x), y(x.y) {}

  gobjglVertex2f
  (
    point2<double> const x
  )
    : x(x.x), y(x.y) {}

  void draw()
    { GOBJDEBUGCODE glVertex2f(x,y); }
};

/*!
\brief A 2D OpenGL vertex with double type.
\par Example
\verbatim
  // Write a point to the global graphics container.
  gobjpush( new gobjglVertex2d(point2<double>(0.2,0.3)) );
\endverbatim
*/
class gobjglVertex2d : public gobj
{
public:

  /** The x coordinate. */
  GLdouble x;
  /** The y coordinate. */
  GLdouble y;

  /** Construct a 2D GLdouble vertex from doubles. */
  gobjglVertex2d
  (
    doublec x_, 
    doublec y_
  )
    : x(x_), y(y_) {}

  /** Construct a 2D GLdouble vertex from floats. */
  gobjglVertex2d
  (
    point2<float> const x
  )
    : x(x.x), y(x.y) {}

  /** Construct a 2D GLdouble vertex from doubles. */
  gobjglVertex2d
  (
    point2<double> const x
  )
    : x(x.x), y(x.y) {}

  /** Send the vertex down the GL pipeline. */
  void draw()
    { GOBJDEBUGCODE glVertex2d(x,y); }
};


/*!
\brief Sets the current matrix to the 4 by 4 identity matrix.
*/
class gobjglLoadIdentity : public gobj
{
public:

  /** Load the identity matrix into the current OpenGL matrix. */
  void draw()
    { GOBJDEBUGCODE glLoadIdentity(); }
};

/*!
\brief Pushes all matrixes in the stack down one level,
 copying the top.

\par Example
\verbatim
  gobjpush( new gobjglPushMatrix() );
  ...
  gobjpush( new gobjglPopMatrix() );
\endverbatim
*/
class gobjglPushMatrix : public gobj
{
public:
  void draw()
    { GOBJDEBUGCODE glPushMatrix(); }
};

/*!
\brief Pops the top matrix off the stack.
*/
class gobjglPopMatrix : public gobj
{
public:
  void draw()
    { GOBJDEBUGCODE glPopMatrix(); }
};

/*!
\brief Turn on graphics states. 

\par Example
\verbatim
  gobjpush( new gobjglEnable(GL_LIGHTING) );
  ...
  gobjpush( new gobjglDisable(GL_LIGHTING) );
\endverbatim
*/
class gobjglEnable : public gobj
{
public:

  /** The OpenGL capability being enabled. */
  GLenum capability;

  /** Pass in what switch that you want to turn on. */
  gobjglEnable(GLenum capability_)
    : capability(capability_) {}

  /** Turn the switch on. */
  void draw()
    { GOBJDEBUGCODE glEnable(capability); }
};

/*!
\brief Turn off graphics states. 

  This is often used with pushing the states onto
  a stack before changing them. OpenGL is a state machine
  so this operation changes the OpenGL state.
*/
class gobjglDisable : public gobj
{
public:

  /** The OpenGL capability being disabled. 
    For example GL_LIGHTING. */
  GLenum capability;

  /** Pass in what switch that you want to turn off. */
  gobjglDisable(GLenum capability_)
    : capability(capability_) {}
  /** Construct from string. */  
  gobjglDisable(stringc & arg);
  /** Construct from string. */  
  boolc serializeInverse(stringc & arg);

  /** Turn the switch off. */
  void draw()
    { GOBJDEBUGCODE glDisable(capability); }
};

/**
\brief Saves all the attributes indicated by bits in the mask.

\par Example
\verbatim
  gobjpush( new gobjglPushAttrib(GL_LIGHTING) );
  gobjpush( new gobjglPushAttrib(GL_CURRENT_BIT) );
  ...
  gobjpush( new gobjglPopAttrib() );
  gobjpush( new gobjglPopAttrib() );
\endverbatim

GL_ACCUM_BUFFER_BIT, GL_ALL_ATTRIB_BITS, GL_COLOR_BUFFER_BIT,
  GL_CURRENT_BIT, GL_DEPTH_BUFFER_BIT, GL_ENABLE_BIT,
  GL_EVAL_BIT, GL_FOG_BIT, GL_HINT_BIT, GL_LIGHTING_BIT, 
  GL_LINE_BIT, GL_LIST_BIT, GL_PIXEL_MODE_BIT, GL_POLYGON_BIT,
  GL_POLYGON_STRIPPLE_BIT, GL_TEXTURE_BIT, GL_TRANSFORM_BIT,
  GL_VIEWPORT_BIT, GL_CLIENT_PIXEL_STORE_BIT, 
  GL_CLIENT_VERTEX_ARRAY_BIT, GL_AL_CLIENT_ATTRIB_BITS
*/
class gobjglPushAttrib : public gobj
{
public:

  GLbitfield mask;

  /** Save the contents of an OpenGL register to a stack. */
  gobjglPushAttrib(GLbitfield mask_)
    : mask(mask_) {}

  gobjglPushAttrib(stringc & arg);

  /** Construct from string, limited support. */
  boolc serializeInverse(stringc & arg);

  /** Push the register pointed to by mask onto the stack. */
  void draw()
    { GOBJDEBUGCODE glPushAttrib(mask); }
};

/*!
\brief Restores the values of those state variables that were 
       saved with the last gobjglPushAttrib .
*/
class gobjglPopAttrib : public gobj
{
public:
  /** Pop the attribute stack. */
  void draw()
    { GOBJDEBUGCODE glPopAttrib(); }
};

class gobjglRotatef : public gobj
{
public:

  GLfloat theta;
  GLfloat x;
  GLfloat y;
  GLfloat z;

  gobjglRotatef
  (
    GLfloat const theta_,
    GLfloat const x_, 
    GLfloat const y_,
    GLfloat const z_
  )
    : theta(theta_), x(x_), y(y_), z(z_) {}

  void draw()
    { GOBJDEBUGCODE glRotatef(theta,x,y,z); }
};

class gobjglRotated : public gobj
{
public:

  GLdouble theta;
  GLdouble x;
  GLdouble y;
  GLdouble z;

  gobjglRotated
  (
    GLdouble const theta_,
    GLdouble const x_, 
    GLdouble const y_,
    GLdouble const z_
  )
    : theta(theta_), x(x_), y(y_), z(z_) {}

  void draw()
    { GOBJDEBUGCODE glRotated(theta,x,y,z); }
};
   
class gobjglTranslatef : public gobj
{
public:

  GLfloat x;
  GLfloat y;
  GLfloat z;

  gobjglTranslatef
  (
    GLfloat const x_, 
    GLfloat const y_,
    GLfloat const z_
  )
    : x(x_), y(y_), z(z_) {}

  gobjglTranslatef
  (
    point3<float> const & p
  )
    : x(p.x), y(p.y), z(p.z) {}

  gobjglTranslatef
  (
    point3<double> const & p
  )
    : x(p.x), y(p.y), z(p.z) {}

  void draw()
    { GOBJDEBUGCODE glTranslatef(x,y,z); }
};

class gobjglTranslated : public gobj
{
public:

  GLdouble x;
  GLdouble y;
  GLdouble z;

  gobjglTranslated
  (
    GLdouble const x_, 
    GLdouble const y_,
    GLdouble const z_
  )
    : x(x_), y(y_), z(z_) {}

  gobjglTranslated
  (
    point3<float> const & p
  )
    : x(p.x), y(p.y), z(p.z) {}

  gobjglTranslated
  (
    point3<double> const & p
  )
    : x(p.x), y(p.y), z(p.z) {}

  void draw()
    { GOBJDEBUGCODE glTranslated(x,y,z); }
};

class gobjglVertex3f : public gobj
{
public:

  float x;
  float y;
  float z;

  gobjglVertex3f
  (
    floatc x_, 
    floatc y_,
    floatc z_
  )
    : x(x_), y(y_), z(z_) {}

  gobjglVertex3f
  (
    point3<float> const & x
  )
    : x(x.x), y(x.y), z(x.z) {}

  gobjglVertex3f
  (
    point3<double> const & x
  )
    : x(x.x), y(x.y), z(x.z) {}

  gobjglVertex3f
  (
    point2<float> const & x
  )
    : x(x.x), y(x.y), z(0.0) {}

  gobjglVertex3f
  (
    point2<double> const & x
  )
    : x(x.x), y(x.y), z(0.0) {}

  /** Construct from string. */      
  gobjglVertex3f(stringc & arg);

  /** Construct from string. */      
  boolc serializeInverse(stringc & arg); 

  void draw()
    { GOBJDEBUGCODE glVertex3f(x,y,z); }


};

class gobjglVertex3d : public gobj
{
public:

  GLdouble x;
  GLdouble y;
  GLdouble z;

  gobjglVertex3d
  (
    doublec x_, 
    doublec y_,
    doublec z_
  )
    : x(x_), y(y_), z(z_) {}

  gobjglVertex3d
  (
    point3<float> const & x
  )
    : x(x.x), y(x.y), z(x.z) {}

  gobjglVertex3d
  (
    point3<double> const & x
  )
    : x(x.x), y(x.y), z(x.z) {}

  gobjglVertex3d
  (
    point2<float> const & x
  )
    : x(x.x), y(x.y), z(0.0) {}

  gobjglVertex3d
  (
    point2<double> const & x
  )
    : x(x.x), y(x.y), z(0.0) {}

  void draw()
    { GOBJDEBUGCODE glVertex3d(x,y,z); }
};

class gobjglNormal3f : public gobj
{
public:

  point3<float> p;

  gobjglNormal3f
  (
    floatc x_, 
    floatc y_,
    floatc z_
  )
    : p( point3<float>(x_,y_,z_) ) {}

  gobjglNormal3f( point3<float> const & p_)
    : p(p_) {}

  gobjglNormal3f( point3<double> const & p_)
    : p(p_.x,p_.y,p_.z) {}

  void draw()
    { GOBJDEBUGCODE glNormal3f(p.x,p.y,p.z); }
};

class gobjglutSolidCube : public gobj
{
public:

  GLdouble size;

  gobjglutSolidCube(GLdouble size_);

  void draw();
};

class gobjglutWireCube : public gobj
{
public:

  GLdouble size;

  gobjglutWireCube(GLdouble size_);

  void draw();
};

class gobjglutSolidCone : public gobj
{
public:

  GLdouble base;
  GLdouble height;
  GLint slices;
  GLint stacks;

  gobjglutSolidCone
  (
    GLdouble base_,
    GLdouble height_,
    GLint slices_,
    GLint stacks_
  );

  void draw();
};

class gobjglutWireCone : public gobj
{
public:

  GLdouble base;
  GLdouble height;
  GLint slices;
  GLint stacks;

  gobjglutWireCone
  (
    GLdouble base_,
    GLdouble height_,
    GLint slices_,
    GLint stacks_
  );

  void draw();
};

class gobjglutSolidTeapot : public gobj
{
public:

  GLdouble size;

  gobjglutSolidTeapot(GLdouble size_);

  void draw();
};

class gobjglutWireTeapot : public gobj
{
public:

  GLdouble size;

  gobjglutWireTeapot(GLdouble size_);

  void draw();
};

class gobjglutSolidSphere : public gobj
{
public:

  GLdouble radius;
  GLint slices;
  GLint stacks;

  gobjglutSolidSphere
  (
    GLdouble radius_,
    GLint slices_,
    GLint stacks_
  );

  void draw();
};

class gobjglutWireSphere : public gobj
{
public:

  GLdouble radius;
  GLint slices;
  GLint stacks;

  gobjglutWireSphere
  (
    GLdouble radius_,
    GLint slices_,
    GLint stacks_
  );

  void draw();
};

class gobjglutSolidDodecahedron : public gobj
{
public:

  gobjglutSolidDodecahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutSolidDodecahedron(); }
};

class gobjglutSolidTetrahedron: public gobj
{
public:

  gobjglutSolidTetrahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutSolidTetrahedron(); }
};

class gobjglutSolidIcosahedron: public gobj
{
public:

  gobjglutSolidIcosahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutSolidIcosahedron(); }
};

class gobjglutSolidOctahedron: public gobj
{
public:

  gobjglutSolidOctahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutSolidOctahedron(); }
};

class gobjglutWireDodecahedron : public gobj
{
public:

  gobjglutWireDodecahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutWireDodecahedron(); }
};

class gobjglutWireTetrahedron: public gobj
{
public:

  gobjglutWireTetrahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutWireTetrahedron(); }
};

class gobjglutWireIcosahedron: public gobj
{
public:

  gobjglutWireIcosahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutWireIcosahedron(); }
};

class gobjglutWireOctahedron: public gobj
{
public:

  gobjglutWireOctahedron() {}
  void draw()  
    { GOBJDEBUGCODE glutWireOctahedron(); }
};

/*
\brief Solid donut.
*/
class gobjglutSolidTorus : public gobj
{
public:

  GLdouble innerRadius; 
  GLdouble outerRadius; 
  GLint nsides; 
  GLint rings;

  gobjglutSolidTorus
  (
    GLdouble innerRadius_, 
    GLdouble outerRadius_, 
    GLint nsides_, 
    GLint rings_
  );

  void draw();
};

/*
\brief Wire donut.
*/
class gobjglutWireTorus : public gobj
{
public:

  GLdouble innerRadius; 
  GLdouble outerRadius; 
  GLint nsides; 
  GLint rings;

  gobjglutWireTorus
  (
    GLdouble innerRadius_, 
    GLdouble outerRadius_, 
    GLint nsides_, 
    GLint rings_
  );

  void draw();
};

/*!
\brief Dashed lines.
*/
class gobjglLineStipple : public gobj
{
public:

  /** Stretches the pattern by multiplying each subseries of
      consecutive 1s or 0s. */
  GLint factor;
  GLushort pattern;

  gobjglLineStipple(GLint factor_, GLushort pattern_)
    : factor(factor_), pattern(pattern_) {}

  void draw()
    { GOBJDEBUGCODE glLineStipple(factor,pattern); }
};

/*!
\brief Transparency.
\par Example
\verbatim
  gobjpush(new gobjglBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA));
  gobjpush(new gobjglEnable(GL_BLEND));
  gobjpush(new gobjglColor4ub(255,215,0,40));
  gobjpush(new d3halfspacedisplay<HS>(h.halfspace));
  gobjpush(new gobjglDisable(GL_BLEND));
\endverbatim
*/
class gobjglBlendFunc : public gobj
{
public:

  GLenum sfactor;
  GLenum dfactor;

  gobjglBlendFunc(GLenum sfactor_, GLenum dfactor_)
    : sfactor(sfactor_), dfactor(dfactor_) {}

  void draw()
    { GOBJDEBUGCODE glBlendFunc(sfactor,dfactor); }
};

class gobjglGenLists : public gobj
{
public:

  GLuint listName;
  GLsizei range;

  gobjglGenLists(GLsizei range_=1)
    : range(range_) {}

  void draw()
    { GOBJDEBUGCODE listName = glGenLists(range); }

};

class gobjglNewList : public gobj
{
  
  GLuint list;
  GLenum mode;

  gobjglNewList(GLuint list_, GLenum mode_)
    : list(list_), mode(mode_) {}

  void draw()
    { GOBJDEBUGCODE if (list!=0) glNewList(list,mode); }

};

class gobjglEndList : public gobj
{
public:

  void draw()
    { GOBJDEBUGCODE glEndList(); }
};

class gobjglMatrixMode : public gobj
{
public:

  GLenum mode;

  gobjglMatrixMode( GLenum mode_ )
    : mode(mode_) {}

  void draw()
    { GOBJDEBUGCODE glMatrixMode(mode); }
};

class gobjglLoadMatrixf : public gobj
{
public:

  GLfloat const * matrix;

  gobjglLoadMatrixf( GLfloat const * matrix_ )
    : matrix(matrix_) {}

  void draw()
    { GOBJDEBUGCODE glLoadMatrixf(matrix); }
};

class gobjglLoadMatrixd : public gobj
{
public:

  GLdouble const * matrix;

  gobjglLoadMatrixd( GLdouble const * matrix_ )
    : matrix(matrix_) {}

  void draw()
    { GOBJDEBUGCODE glLoadMatrixd(matrix); }
};

class gobjglMultMatrixf : public gobj
{
public:

  GLfloat const * matrix;

  gobjglMultMatrixf( GLfloat const * matrix_ )
    : matrix(matrix_) {}

  void draw()
    { GOBJDEBUGCODE glMultMatrixf(matrix); }
};

class gobjglMultMatrixd : public gobj
{
public:

  GLdouble const * matrix;

  gobjglMultMatrixd( GLdouble const * matrix_ )
    : matrix(matrix_) {}

  void draw()
    { GOBJDEBUGCODE glMultMatrixd(matrix); }
};
  
class gobjglOrtho : public gobj
{
public:

  GLdouble left;
  GLdouble right;
  GLdouble bottom;
  GLdouble top;
  GLdouble near;
  GLdouble far;

  gobjglOrtho
  (
    GLdouble const left_,
    GLdouble const right_,
    GLdouble const bottom_,
    GLdouble const top_,
    GLdouble const near_,
    GLdouble const far_
  )
    : left(left_), right(right_), bottom(bottom_), top(top_),
      near(near_), far(far_) {}

  void draw()
    { GOBJDEBUGCODE glOrtho(left,right,bottom,top,near,far); }
};

class gobjglViewport : public gobj
{
public:

  GLint x;
  GLint y;
  GLsizei width;
  GLsizei height;

  gobjglViewport
  (
    GLint x_,
    GLint y_,
    GLsizei width_,
    GLsizei height_
  )
    : x(x_), y(y_), width(width_), height(height_) {}

  void draw()
    { GOBJDEBUGCODE glViewport(x,y,width,height); }
};

class gobjglDepthRange : public gobj
{
public:

  GLclampd near;
  GLclampd far;

  gobjglDepthRange(GLclampd near_, GLclampd far_)
    : near(near_), far(far_) {}

  void draw()
    { GOBJDEBUGCODE glDepthRange(near,far); }
};

class gobjglClipPlane : public gobj
{
public:

  GLenum plane;
  GLdouble const * equation;

  gobjglClipPlane
  (
    GLenum plane_,
    GLdouble const * equation_
  )
    : plane(plane_), equation(equation_) {}

  void draw()
    { GOBJDEBUGCODE glClipPlane(plane,equation); }
};


class gobjgluNewQuadric : public gobj
{
public:

  GLUquadricObj* qobj;
  
  void draw()
    { GOBJDEBUGCODE qobj = gluNewQuadric(); }
};

class gobjgluDeleteQuadric : public gobj
{
public:

  GLUquadricObj* & qobj;

  gobjgluDeleteQuadric(GLUquadricObj * & qobj_)
    : qobj(qobj_) {}

  void draw()
    { GOBJDEBUGCODE gluDeleteQuadric(qobj); }
};

class gobjgluQuadricOrientation : public gobj
{
public:

  GLUquadricObj* & qobj;

  GLenum orientation;

  gobjgluQuadricOrientation(GLUquadricObj * & qobj_, GLenum orientation_)
   : qobj(qobj_), orientation(orientation_) {}

  void draw()
    { GOBJDEBUGCODE gluQuadricOrientation(qobj,orientation); }
};

class gobjgluQuadricNormals : public gobj
{
public:

  GLUquadricObj* & qobj;

  GLenum normals;

  gobjgluQuadricNormals(GLUquadricObj* qobj_, GLenum normals_)
    : qobj(qobj_), normals(normals_) {}

  void draw()
    { GOBJDEBUGCODE gluQuadricNormals(qobj,normals); }

};

class gobjgluQuadricTexture : public gobj
{
public:

  GLUquadricObj * & qobj;

  GLboolean textureCoords;

  gobjgluQuadricTexture
  (
    GLUquadricObj * & qobj_, 
    GLboolean textureCoords_
  )
    : qobj(qobj_), textureCoords(textureCoords_) {}

  void draw()
    { GOBJDEBUGCODE gluQuadricTexture(qobj,textureCoords); }
};

/*!
\brief Draw a sphere.

\par Example 
From http://in4k.untergrund.net/index.php?title=Mega_Small_(Almost_Free)_Geometry
\verbatim
gluSphere (q, 0.8, 20, 20);    // a sphere
gluSphere (q, 0.8, 20, 20);    // a smartie ...when scaled of course
gluSphere (q, 0.8, 20, 20);    // an ellipsoid...same here, fix later
gluSphere (q, 0.8, 3, 20);     // a seed like shape?
gluSphere (q, 0.8, 4, 20);     // an ikea paper lamp?
gluSphere (q, 0.8, 4, 2);      // diamond
gluSphere (q, 0.8, 3, 3);      // triangular crystal
gluSphere (q, 0.8, 6, 3);      // quartz crystal
\endverbatim
*/
class gobjgluSphere : public gobj
{
public:

  GLUquadricObj* & qobj;

  GLdouble radius;

  GLint slices;

  GLint stacks;

  gobjgluSphere
  (
    GLUquadricObj * & qobj_,
    GLdouble radius_,
    GLint slices_,
    GLint stacks_
  ) : qobj(qobj_), radius(radius_), slices(slices_), 
    stacks(stacks_) {}

  void draw()
    { GOBJDEBUGCODE gluSphere(qobj,radius,slices,stacks); }
};

/*!
\brief Draw a cylinder.

\par Example 
From http://in4k.untergrund.net/index.php?title=Mega_Small_(Almost_Free)_Geometry
\verbatim
gluCylinder (q, 0.4, 0.4, 0.8, 20, 20);  // cylinder
gluCylinder (q, 0.4, 0.4, 0.8, 4, 20);   // square tube
gluCylinder (q, 0.4, 0.4, 0.8, 3, 20);   // triangular tube
gluCylinder (q, 0.4, 0.4, 0.8, 6, 20);   // hexagonal tube
gluCylinder (q, 0.4, 0.0, 0.8, 20, 20);  // cone
gluCylinder (q, 0.4, 0.0, 0.8, 4, 20);   // square base pyramid
gluCylinder (q, 0.4, 0.0, 0.8, 3, 20);   // triangular based pyramid
gluCylinder (q, 0.4, 0.0, 0.8, 6, 20);   // hexagonal based pyramid
\endverbatim
*/    
class gobjgluCylinder : public gobj
{
public:

  GLUquadricObj * & qobj;

  GLdouble baseRadius;

  GLdouble topRadius;
  
  GLdouble height;

  GLint slices;

  GLint stacks;

  gobjgluCylinder
  (
    GLUquadricObj * & qobj_,
    GLdouble baseRadius_,
    GLdouble topRadius_,
    GLdouble height_,
    GLint slices_,
    GLint stacks_
  )
    : qobj(qobj_), baseRadius(baseRadius_), 
    topRadius(topRadius_), height(height_),
    slices(slices_), stacks(stacks_) {}

  void draw()
    { GOBJDEBUGCODE gluCylinder(qobj,baseRadius,topRadius,height,slices,stacks); }
};

/*!
\brief Draw a disc.

\par Example 
From http://in4k.untergrund.net/index.php?title=Mega_Small_(Almost_Free)_Geometry
\verbatim
gluDisk (q, 0.0, 0.8, 30, 1);  // Solid Circle
gluDisk (q, 0.6, 0.8, 30, 1);  // ring
gluDisk (q, 0.6, 0.8, 4, 1);   // hollow square
gluDisk (q, 0.6, 0.8, 3, 1);   // hollow triangle
gluDisk (q, 0.0, 0.8, 3, 1);   // solid triangle
gluDisk (q, 0.0, 0.8, 4, 1);   // solid square
gluDisk (q, 0.0, 0.8, 6, 1);   // solid Hexagon
gluDisk (q, 0.6, 0.8, 6, 1);   // hollow hexagon (think beehive)
\endverbatim
*/
class gobjgluDisk : public gobj
{
public:

  GLUquadricObj * & qobj;
  
  GLdouble innerRadius;

  GLdouble outerRadius;

  GLint slices;
  
  GLint rings;

  gobjgluDisk
  (
    GLUquadricObj * & qobj_,
    GLdouble innerRadius_,
    GLdouble outerRadius_,
    GLint slices_,
    GLint rings_
  )
    : qobj(qobj_), innerRadius(innerRadius_), 
    outerRadius(outerRadius_), slices(slices_), 
    rings(rings_) {}

  void draw()
    { GOBJDEBUGCODE gluDisk(qobj,innerRadius,outerRadius,slices,rings); }
};

/*!
\brief Draw a partial disk.

\par Example 
From http://in4k.untergrund.net/index.php?title=Mega_Small_(Almost_Free)_Geometry
\verbatim
gluPartialDisk (q, 0.0, 0.8, 30, 1, -45, 270);  // pacman
gluPartialDisk (q, 0.6, 0.8, 30, 1,0,180);      // half ring
gluPartialDisk (q, 0.6, 0.8, 3, 1,0,270);       // square ring partial
gluPartialDisk (q, 0.6, 0.8, 2, 1,0, 240);      // triangle ring partial
gluPartialDisk (q, 0.0, 0.8, 2, 1, 0, 240);     // arrow head 
gluPartialDisk (q, 0.0, 0.8, 3, 1,0,270);       // square partial
gluPartialDisk (q, 0.0, 0.8, 5, 1,0,300);       // Hexagon partial
gluPartialDisk (q, 0.6, 0.8, 5, 1,0,300);       // Hexagon ring partial
\endverbatim
*/
class gobjgluPartialDisk : public gobj
{
public:

  GLUquadricObj * & qobj;

  GLdouble innerRadius;

  GLdouble outerRadius;

  GLint slices;

  GLint rings;

  GLdouble startAngle;

  GLdouble sweepAngle;

  gobjgluPartialDisk
  (
    GLUquadricObj * & qobj_,
    GLdouble innerRadius_,
    GLdouble outerRadius_,
    GLint slices_,
    GLint rings_,
    GLdouble startAngle_,
    GLdouble sweepAngle_
  )
    : qobj(qobj_), innerRadius(innerRadius_), 
    outerRadius(outerRadius_), slices(slices_),
    startAngle(startAngle_), sweepAngle(sweepAngle_) {}

  void draw()
    { GOBJDEBUGCODE gluPartialDisk(qobj,innerRadius,outerRadius,slices,rings,
      startAngle,sweepAngle); }
};

class gobjgluOrtho2D : public gobj
{
public:

  GLdouble left;
  GLdouble right;
  GLdouble bottom;
  GLdouble top;

  gobjgluOrtho2D
  (
    GLdouble const left_,
    GLdouble const right_,
    GLdouble const bottom_,
    GLdouble const top_
  )
    : left(left_), right(right_), bottom(bottom_), top(top_) {}

  void draw()
    { GOBJDEBUGCODE gluOrtho2D(left,right,bottom,top); }
};

class gobjgluPerspective : public gobj
{
public:

  GLdouble fovy;
  GLdouble aspect;
  GLdouble near;
  GLdouble far;

  gobjgluPerspective
  (
    GLdouble const fovy_,
    GLdouble const aspect_,
    GLdouble const near_,
    GLdouble const far_
  )
    : fovy(fovy_), aspect(aspect_), near(near_), far(far_)
    {}

  void draw()
    { GOBJDEBUGCODE gluPerspective(fovy,aspect,near,far); }
};

class gobjglFlush : public gobj
{
public:

  void draw()
    { GOBJDEBUGCODE glFlush(); }

};

class gobjglClear : public gobj
{
public:

  GLbitfield mask;

  gobjglClear(GLbitfield mask_)
    : mask(mask_) {}

  void draw()
    { GOBJDEBUGCODE glClear(mask); }
};

class gobjglClearColor : public gobj
{
public:
  
  GLclampf red;
  GLclampf green;
  GLclampf blue;
  GLclampf alpha;
  
  gobjglClearColor
  (
    GLclampf red_,
    GLclampf green_,
    GLclampf blue_,
    GLclampf alpha_
  )
    : red(red_), green(green_), blue(blue_), alpha(alpha_) {}

  gobjglClearColor(point3<double> const & p)
    : red(p.x), green(p.y), blue(p.z), alpha(0.0) {}

  void draw()
    { GOBJDEBUGCODE glClearColor(red,green,blue,alpha); }

};

class gobjglClearIndex : public gobj
{
public:

  GLfloat index;

  gobjglClearIndex(GLfloat index_)
    : index(index_) {}

  void draw()
    { GOBJDEBUGCODE glClearIndex(index); }

};

class gobjglClearDepth : public gobj
{
public:

  GLclampd depth;

  gobjglClearDepth(GLclampd depth_)
    : depth(depth_) {}

  void draw()
    { GOBJDEBUGCODE glClearDepth(depth); }

};

class gobjglClearStencil : public gobj
{
public:

  // ??? on name
  GLint stencil;

  gobjglClearStencil(GLint stencil_)
    : stencil(stencil_) {}

  void draw()
    { GOBJDEBUGCODE glClearStencil(stencil); }

};

class gobjglClearAccum : public gobj
{
public:
  
  GLfloat red;
  GLfloat green;
  GLfloat blue;
  GLfloat alpha;
  
  gobjglClearAccum
  (
    GLfloat red_,
    GLfloat green_,
    GLfloat blue_,
    GLfloat alpha_
  )
    : red(red_), green(green_), blue(blue_), alpha(alpha_) {}

  void draw()
    { GOBJDEBUGCODE glClearAccum(red,green,blue,alpha); }

};



#endif



