#ifndef TETRAHEDRONDRAW_H
#define TETRAHEDRONDRAW_H

#include <gobj.h>

#include <tetrahedron.h>


/*!
\brief  Create geometry from tetrahedron.  Send to gobj
        graphics stack for processing.
*/
template< typename T, typename D >
class tetrahedrondraw : public tetrahedron<T,D> 
{
  void displaywindingside
  (
    gobjContainer & c,
    T const & N, 
    T const & P0, 
    T const & P1, 
    T const & P2 
  ) const;
public:

  /* Constructor: tetrahedron's points.  The order is 
     important.

     The first three points are the tetrahedrons base with an
     clockwise winding defining a normal pointing inside the 
     tetrahedron. The fourth point is above this triangle. 
     eg the base triangle can see the fourth point. */
  tetrahedrondraw
  (
    T const p0_,
    T const p1_,
    T const p2_,
    T const p3_
  );

  /* Call the function for any of these options. */

  /* Display the tetrahedron edges. */
  void displayedges() const;

  /* Displays the base which is the first three points that
     form the tetrahedron. */
  void displaybase() const;

  /* Draws the winding on the outside of the tetrahedron.
     RGB correspons with the colors at the vertex to indicate
     the triangles winding. */
  void displaywinding() const;

};


// --------------------------------------------------------- 
// Implementation


template< typename T, typename D >
void tetrahedrondraw<T,D>::displaywindingside
(
  gobjContainer & c,
  T const & N, 
  T const & P0, 
  T const & P1, 
  T const & P2 
) const 
{
  c.push( new gobjglColor3ub(255,0,0) ); 
  c.push( new gobjglNormal3f(N) ); 
  c.push( new gobjglVertex3f(P0) ); 
  c.push( new gobjglColor3ub(0,255,0) ); 
  c.push( new gobjglNormal3f(N) ); 
  c.push( new gobjglVertex3f(P1) ); 
  c.push( new gobjglColor3ub(0,0,255) ); 
  c.push( new gobjglNormal3f(N) ); 
  c.push( new gobjglVertex3f(P2) ); 
}

#define TET3SIDE(H3,P0,P1,P2) \
{ \
  T nH3(tetrahedron<T,D>::H3.normal); \
  displaywindingside(c,nH3,tetrahedron<T,D>::P0,tetrahedron<T,D>::P1,tetrahedron<T,D>::P2); \
}


template< typename T, typename D >
void tetrahedrondraw<T,D>::displaywinding() const
{
  gobjContainer & c = * gobjContainer::global;

  c.push( new gobjglEnable(GL_LIGHTING) );

  c.push( new gobjglBegin(GL_TRIANGLES) );
 
  TET3SIDE(hi[3],pi[0],pi[1],pi[2])

  TET3SIDE(hi[0],pi[2],pi[1],pi[3])

  TET3SIDE(hi[1],pi[3],pi[0],pi[2])

  TET3SIDE(hi[2],pi[1],pi[0],pi[3])

  c.push( new gobjglEnd() );
}

template< typename T, typename D >
void tetrahedrondraw<T,D>::displaybase() const
{
  gobjContainer* c = gobjContainer::global;
  c->push( new gobjglPushAttrib(GL_CURRENT_BIT) );
  c->push( new gobjglPushAttrib(GL_LIGHTING_BIT) );

  T N(tetrahedron<T,D>::hi[3].normal);
  T N2(N);
  N2 *= -1.0;

  c->push( new gobjglBegin(GL_TRIANGLES) );

  c->push( new gobjglColor3ub(255,0,0) );
  c->push( new gobjglNormal3f(N) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[0]) );
  c->push( new gobjglColor3ub(0,255,0) );
  c->push( new gobjglNormal3f(N) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[1]) );
  c->push( new gobjglColor3ub(0,0,255) );
  c->push( new gobjglNormal3f(N) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[2]) );


  c->push( new gobjglColor3ub(0,0,255) );
  c->push( new gobjglNormal3f(N2) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[2]) );
  c->push( new gobjglColor3ub(255,255,0) );
  c->push( new gobjglNormal3f(N2) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[1]) );
  c->push( new gobjglColor3ub(255,0,0) );
  c->push( new gobjglNormal3f(N2) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[0]) );






  c->push( new gobjglEnd() );

  c->push( new gobjglPopAttrib() );
  c->push( new gobjglPopAttrib() );
}



template< typename T, typename D >
void tetrahedrondraw<T,D>::displayedges() const
{
  gobjContainer* c = gobjContainer::global;
//  c->push_back( new gobjglPushAttrib(GL_CURRENT_BIT) );
//  c->push_back( new gobjglPushAttrib(GL_LIGHTING_BIT) );

  //c->push_back( new gobjglColor3f(0.6,0.3,0.0) );
  c->push( new gobjglColor3ub(0,0,255) );
  c->push( new gobjglDisable(GL_LIGHTING) );
  c->push( new gobjglBegin(GL_LINES) );

  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[0]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[1]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[0]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[2]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[0]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[3]) );

  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[1]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[2]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[1]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[3]) );

  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[2]) );
  c->push( new gobjglVertex3f(tetrahedron<T,D>::pi[3]) );

  c->push( new gobjglEnd() );

//  c->push_back( new gobjglPopAttrib() );
//  c->push_back( new gobjglPopAttrib() );
}



template< typename T, typename D >
tetrahedrondraw<T,D>::tetrahedrondraw
(
  T const p0_,
  T const p1_,
  T const p2_,
  T const p3_
)
  : tetrahedron<T,D>(p0_,p1_,p2_,p3_)
{
}


#endif


