#ifndef TRIANGLES3TDISPLAY_H
#define TRIANGLES3TDISPLAY_H

#include <GL/glut.h>

#include <print.h>
#include <point.h>
#include <gobj.h>
#include <OpenGLtemplated.h>




/*!
\brief Base class for drawing triangles as index points 
  using OpenGL commands.

The triangles are represented by integer indexes into a 
  global points stack.The order of the triangles is assumed 
  to be anti-clockwise.
*/
template< typename T, typename W >
class triangles3Tdisplay : public gobj
{
public:

  /** The number of triangles. */
  uint visize;

  /** The indexed triangles. */
  point3<uint> const * vi;

  /** The global points. */
  point3<W> const * pts;

  /** Pass in the geometry to be displayed.*/
  triangles3Tdisplay
  (
    uintc visize_, 
    point3<uint> const * vi_,
    point3<W> const * pts_
  )
    : visize(visize_), vi(vi_), pts(pts_) {}

  /** Draw faceted triangles. */
  void draw()
  {
    GOBJDEBUGCODE
    point3<uint> const * t;
    glBegin(GL_TRIANGLES);
    for (uint i=0; i<visize; ++i)
    {
      t = & vi[i];
      point3<W> const & p0( pts[t->x] );
      glVertex3T<T>()(p0.x,p0.y,p0.z);
      point3<W> const & p1( pts[t->y] );
      glVertex3T<T>()(p1.x,p1.y,p1.z);
      point3<W> const & p2( pts[t->z] );
      glVertex3T<T>()(p2.x,p2.y,p2.z);
    }

    glEnd();
  }

};





/*!
\brief Drawing triangles with normals at the points, 
  using OpenGL commands.
*/
template< typename T, typename W >
class triangles3TdisplayN : public triangles3Tdisplay<T,W>
{
public:

  /** The global points. */
  point3<W> const * normals;

  /** Pass in the geometry to be displayed.*/
  triangles3TdisplayN
  (
    uintc visize_, 
    point3<uint> const * vi_,
    point3<W> const * pts_,
    point3<W> const * normals_
  )
    : triangles3Tdisplay<T,W>(visize_,vi_,pts_), 
    normals(normals_) {}

  /** Draw triangles with normals at each point. */
  void draw()
  {
    GOBJDEBUGCODE
    point3<uint> const * t;
    glBegin(GL_TRIANGLES);
    for (uint i=0; i<triangles3Tdisplay<T,W>::visize; ++i)
    {
      t = & triangles3Tdisplay<T,W>::vi[i];

      point3<W> const & n0( normals[t->x] );
      glNormal3T<T>()(n0.x,n0.y,n0.z);
      point3<W> const & p0( triangles3Tdisplay<T,W>::pts[t->x] );
      glVertex3T<T>()(p0.x,p0.y,p0.z);

      point3<W> const & n1( normals[t->y] );
      glNormal3T<T>()(n1.x,n1.y,n1.z);
      point3<W> const & p1( triangles3Tdisplay<T,W>::pts[t->y] );
      glVertex3T<T>()(p1.x,p1.y,p1.z);

      point3<W> const & n2( normals[t->z] );
      glNormal3T<T>()(n2.x,n2.y,n2.z);
      point3<W> const & p2( triangles3Tdisplay<T,W>::pts[t->z] );
      glVertex3T<T>()(p2.x,p2.y,p2.z);
    }

    glEnd();
  }

};



/*!
\brief Drawing triangles with a normal and color at each 
 point, using OpenGL commands.
*/
template< typename T, typename W, typename C >
class triangles3TdisplayNC : public triangles3Tdisplay<T,W>
{
public:

  /** The global normals. */
  point3<W> const * normals;

  /** The global colors */
  point3<C> const * colors;

  /** Pass in the geometry to be displayed.*/
  triangles3TdisplayNC
  (
    uintc visize_, 
    point3<uint> const * vi_,
    point3<W> const * pts_,
    point3<W> const * normals_,
    point3<C> const * colors_
  )
    : triangles3Tdisplay<T,W>(visize_,vi_,pts_), 
    normals(normals_), colors(colors_) {}

  /** Draw triangles with normals at each point. */
  void draw()
  {
    GOBJDEBUGCODE
    point3<uint> const * t;
    glBegin(GL_TRIANGLES);
    for (uint i=0; i<triangles3Tdisplay<T,W>::visize; ++i)
    {
      t = & triangles3Tdisplay<T,W>::vi[i];

      uintc k0(t->x);
      point3<C> const & c0(colors[k0]);
      glColor3T<C>()(c0.x,c0.y,c0.z);
      point3<W> const & n0( normals[k0] );
      glNormal3T<T>()(n0.x,n0.y,n0.z);
      point3<W> const & p0( triangles3Tdisplay<T,W>::pts[k0] );
      glVertex3T<T>()(p0.x,p0.y,p0.z);

      uintc k1(t->y);
      point3<C> const & c1(colors[k1]);
      glColor3T<C>()(c1.x,c1.y,c1.z);
      point3<W> const & n1( normals[k1] );
      glNormal3T<T>()(n1.x,n1.y,n1.z);
      point3<W> const & p1( triangles3Tdisplay<T,W>::pts[k1] );
      glVertex3T<T>()(p1.x,p1.y,p1.z);

      uintc k2(t->z);
      point3<C> const & c2(colors[k2]);
      glColor3T<C>()(c2.x,c2.y,c2.z);
      point3<W> const & n2( normals[k2] );
      glNormal3T<T>()(n2.x,n2.y,n2.z);
      point3<W> const & p2( triangles3Tdisplay<T,W>::pts[k2] );
      glVertex3T<T>()(p2.x,p2.y,p2.z);
    }

    glEnd();
  }

};



/*!
\brief Drawing triangles with a normal and color at each 
 triangle, using OpenGL commands.
*/
template< typename T, typename W, typename C >
class triangles3TdisplayNCpertriangle 
  : public triangles3Tdisplay<T,W>
{
public:

  /** The global normals. */
  point3<W> const * normals;

  /** The global colors */
  point3<C> const * colors;

  /** Pass in the geometry to be displayed.*/
  triangles3TdisplayNCpertriangle
  (
    uintc visize_, 
    point3<uint> const * vi_,
    point3<W> const * pts_,
    point3<W> const * normals_,
    point3<C> const * colors_
  )
    : triangles3Tdisplay<T,W>(visize_,vi_,pts_), 
    normals(normals_), colors(colors_) {}

  /** Draw triangles with normals at each point. */
  void draw()
  {
    GOBJDEBUGCODE
    point3<uint> const * t;
    glBegin(GL_TRIANGLES);
    for (uint i=0; i<triangles3Tdisplay<T,W>::visize; ++i)
    {
      point3<C> const & c0(colors[i]);
      glColor3T<C>()(c0.x,c0.y,c0.z);

      t = & triangles3Tdisplay<T,W>::vi[i];

      uintc k0(t->x);
      point3<W> const & n0( normals[k0] );
      glNormal3T<T>()(n0.x,n0.y,n0.z);
      point3<W> const & p0( triangles3Tdisplay<T,W>::pts[k0] );
      glVertex3T<T>()(p0.x,p0.y,p0.z);

      uintc k1(t->y);
      point3<W> const & n1( normals[k1] );
      glNormal3T<T>()(n1.x,n1.y,n1.z);
      point3<W> const & p1( triangles3Tdisplay<T,W>::pts[k1] );
      glVertex3T<T>()(p1.x,p1.y,p1.z);

      uintc k2(t->z);
      point3<W> const & n2( normals[k2] );
      glNormal3T<T>()(n2.x,n2.y,n2.z);
      point3<W> const & p2( triangles3Tdisplay<T,W>::pts[k2] );
      glVertex3T<T>()(p2.x,p2.y,p2.z);
    }

    glEnd();
  }

};






/*!
\brief Drawing triangles each with a color, using OpenGL commands.
*/
template< typename T, typename W, typename C >
class triangles3TdisplayCpertriangle : public triangles3Tdisplay<T,W>
{
public:

  /** The global colors. */
  point3<C> const * colors;

  /** Pass in the geometry to be displayed.*/
  triangles3TdisplayCpertriangle
  (
    uintc visize_, 
    point3<uint> const * vi_,
    point3<W> const * pts_,
    point3<W> const * colors_
  )
    : triangles3Tdisplay<T,W>(visize_,vi_,pts_), 
    colors(colors_) {}

  /** Draw triangles each with a color. */
  void draw()
  {
    GOBJDEBUGCODE
    point3<uint> const * t;
    glBegin(GL_TRIANGLES);
    for (uint i=0; i<triangles3Tdisplay<T,W>::visize; ++i)
    {
      point3<C> const & c0(colors[i]);
      glColor3T<C>()(c0.x,c0.y,c0.z);

      t = & triangles3Tdisplay<T,W>::vi[i];

      point3<W> const & p0( triangles3Tdisplay<T,W>::pts[t->x] );
      glVertex3T<T>()(p0.x,p0.y,p0.z);

      point3<W> const & p1( triangles3Tdisplay<T,W>::pts[t->y] );
      glVertex3T<T>()(p1.x,p1.y,p1.z);

      point3<W> const & p2( triangles3Tdisplay<T,W>::pts[t->z] );
      glVertex3T<T>()(p2.x,p2.y,p2.z);
    }

    glEnd();
  }

};




#endif



