#include <stdio.h>
#include "GLGraphics.h"


GLGraphics::GLGraphics(vector <vect3<GLfloat> > *colour_array):
  colours(colour_array)
{
  Rendered=false;
  theLsys=0;
}

void GLGraphics::StoreHexahedron(vector <vect3<float> > *vertex, unsigned short int colour)
{
  //Vertices used for each side of the cube 
  static GLubyte indices[6][4] = {{0,3,2,1}, //bottom
                                  {4,5,6,7}, //top
				  {0,1,5,4}, //front
				  {2,3,7,6}, //back
				  {0,4,7,3}, //left
				  {1,2,6,5}}; //right
  //Storage for each of the 8 vertices
  static GLfloat   ver[24];
  
  if (vertex->size()==8) {    //assume 8 vertices
    vect3<GLfloat>                d1,d2,normal;

    //transfer the data into the "ver" storage array
    for (int i=0;i<8;i++) {
      ver[i*3]=((*vertex)[i])[0];
      ver[i*3+1]=((*vertex)[i])[1];
      ver[i*3+2]=((*vertex)[i])[2];
    };

    //set the colour
    glColor3fv((*colours)[colour%(colours->size())].data);

    //point the GL functions at the storage array
    glVertexPointer(3,GL_FLOAT,0,ver);
    

    /***** calculate normals, then draw each side ******/
    //bottom side
    d1 = (*vertex)[0]-(*vertex)[3];
    d2=(*vertex)[0]-(*vertex)[9];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[0]);
    
    //front side (normal shares bottom edge)
    d2=(*vertex)[0]-(*vertex)[12];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[2]);
    
    //left side (normal shares left edge)
    d1=(*vertex)[21]-(*vertex)[12];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[4]);
    
    //top normal (normal shares top edge)
    d2=(*vertex)[21]-(*vertex)[18];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[1]);
      
    //back side (normal shares *** edge)
    d1=(*vertex)[6]-(*vertex)[18];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[3]);
    
    //right side (normal shares *** edge)
    d2=(*vertex)[6]-(*vertex)[3];
    normal=d1*d2;
    normal.normalize();
    glNormal3fv(normal.data);
    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, indices[5]);
  };
}

void GLGraphics::StoreTriangleStrip(vector <vect3<float> > *vertex, unsigned short int colour)
{
  unsigned int tot=(*vertex).size();
  if (tot>=3) {  // must have >= 3 vertices
    vect3<GLfloat>  d[2],normal;
    
    glBegin(GL_TRIANGLE_STRIP);
      //set the colour
      glColor3fv((*colours)[colour%(colours->size())].data);

      //first 2 vertices are needed to calculate a normal
      d[0] = (*vertex)[1]-(*vertex)[0];
      d[1] = (*vertex)[1]-(*vertex)[2];
      normal=d[0]*d[1];
      normal.normalize();
      glNormal3fv(normal.data);
      glVertex3f((*vertex)[0][0],(*vertex)[0][1],(*vertex)[0][2]);
      glVertex3f((*vertex)[1][0],(*vertex)[1][1],(*vertex)[1][2]);

      //now tackle each of the remaining vertices
      for (unsigned int i=2;i<tot;i++)
	{
	  d[i&1] = (*vertex)[i]-(*vertex)[i-1]; /* d[i&1] alternates 
						   between 0 and 1 on 
						   each pass of the loop */
	  normal=d[0]*d[1];
	  normal.normalize();
	  glNormal3fv(normal.data);
	  glVertex3f((*vertex)[i][0],(*vertex)[i][1],(*vertex)[i][2]);
	};

    glEnd();
  };
}

void GLGraphics::BeginStore()
{    //true if initialisation needed
  Rendered=false;
  theLsys = glGenLists (1);
  if (theLsys==0) { 
    printf("Bugger, could not allocate glList!\n");  
    abort();
  };
  
  glNewList(theLsys, GL_COMPILE);
  glEnableClientState (GL_VERTEX_ARRAY);
}

void GLGraphics::EndStore()
{
  glEndList();
  Rendered=true;
}

void GLGraphics::Output()
{
  if (theLsys!=0) 
    glCallList(theLsys);
  OutputDone=true;
}


void GLGraphics::Clear()
{
  if (theLsys!=0)
    glDeleteLists(theLsys,1);
  theLsys=0;
  Rendered=false;
  OutputDone=false;
}

bool GLGraphics::HasBeenStored()
{
  return Rendered;
}

bool GLGraphics::HasBeenOutput()
{
  return OutputDone;
}


