// pensoc.c
// Penguin Soccer

// Matthew Mundell
// CS4 Graphics Mini-Project

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glut.h>

#define TRUE 1
#define FALSE 0
#define HEIGHT 5
#define PI 3.14159

typedef enum {CHASING, WAITING} penguinstate;

float xangle = 0.0;
float yangle = 0.0;
float posx = 0.0;
float posy = 0.0;
float posz = 0.0;

int width;    			// window width
int height;			// window height

int numvertex;
int pnumface;
int snumface;
int bnumface;
int rnumface;
int numedge;

int lastx = 0;
int lasty = 0;
int firstx = 0;
int firsty = 0;
int distance = 0;
int distancechange = 0;

int forward = FALSE;
int backward = FALSE;
int right = FALSE;
int left = FALSE;
int ftime = 0.0;

float ballx = 0.0;
float ballz = 0.0;

float v1x,v2x,v1y,v2y,v1z,v2z,l1,l2;   //normal calc vars

typedef struct vertex
  {
    float x;
    float y;
    float z;
  } Vertex;

typedef int Triangle [3];

Vertex * pvertices;
Triangle * ptriangles;
Vertex * pnormals;

Vertex * svertices;
Triangle * striangles;

Vertex * bvertices;
Triangle * btriangles;

Vertex * rvertices;
Triangle * rtriangles;
Vertex * rnormals;

Vertex * transformedvertices = NULL;


static GLuint texNames[2];
GLubyte * image;
int imagewidth;
int imageheight;

GLubyte * image2;
int image2width;
int image2height;


void pReadOff (char * filename)
/* no error checking at all - add some in if you feel inclined. */

{
  int i;

  FILE * fl = fopen (filename, "r");
  fscanf (fl, "%d %d %d\n", &numvertex, &pnumface, &numedge);
  
  pvertices = (Vertex *) malloc (sizeof (Vertex) * numvertex);
  ptriangles = (Triangle *) malloc (sizeof (Triangle) * pnumface);
  pnormals = (Vertex *) malloc (sizeof (Vertex) * pnumface);

  for (i = 0; i < numvertex; i++)
    fscanf (fl, "%f %f %f\n",
        &(pvertices[i].x),
        &(pvertices[i].y),
        &(pvertices[i].z));
  for (i = 0; i < pnumface; i++)
    fscanf (fl, "3 %d %d %d\n",
        &(ptriangles[i][0]),
        &(ptriangles[i][1]),
        &(ptriangles[i][2]));

  // beautifull normal calculation (thanks to Wilfred for help)
  for (i = 0; i < pnumface; i++)
    {
	v1x = pvertices[ptriangles[i][1]].x - pvertices[ptriangles[i][0]].x;
	v1y = pvertices[ptriangles[i][1]].y - pvertices[ptriangles[i][0]].y;
	v1z = pvertices[ptriangles[i][1]].z - pvertices[ptriangles[i][0]].z;
     	l1 = sqrt( (v1x*v1x) + (v1y*v1y) + (v1z*v1z) );

	v2x = pvertices[ptriangles[i][1]].x - pvertices[ptriangles[i][0]].x;
	v2y = pvertices[ptriangles[i][1]].y - pvertices[ptriangles[i][0]].y;
	v2z = pvertices[ptriangles[i][1]].z - pvertices[ptriangles[i][0]].z;
     	l2 = sqrt( (v2x*v2x) + (v2y*v2y) + (v2z*v2z) );

	pnormals[i].x = (v1y/l1 * v2z/l2) - (v1z/l1*v2y/l2);
	pnormals[i].y = (v1z/l1 * v2x/l2) - (v1x/l1*v2z/l2);
	pnormals[i].z = (v1x/l1 * v2y/l2) - (v1y/l1*v2x/l2);

    }

  fclose (fl);
}

void rReadOff (char * filename)
/* no error checking at all - add some in if you feel inclined. */
// should do both readoff's with one func maybe time later
{
  int i;

  FILE * fl = fopen (filename, "r");
  fscanf (fl, "%d %d %d\n", &numvertex, &rnumface, &numedge);

  rvertices = (Vertex *) malloc (sizeof (Vertex) * numvertex);
  rtriangles = (Triangle *) malloc (sizeof (Triangle) * rnumface);
  rnormals = (Vertex *) malloc (sizeof (Vertex) * rnumface);
  for (i = 0; i < numvertex; i++)
    fscanf (fl, "%f %f %f\n",
        &(rvertices[i].x),
        &(rvertices[i].y),
        &(rvertices[i].z));
  for (i = 0; i < rnumface; i++)
    fscanf (fl, "3 %d %d %d\n",
        &(rtriangles[i][0]),
        &(rtriangles[i][1]),
        &(rtriangles[i][2]));

  // beautifull normal calculation (thanks to Wilfred for help)
  for (i = 0; i < rnumface; i++)
    {
	v1x = rvertices[rtriangles[i][1]].x - rvertices[rtriangles[i][0]].x;
	v1y = rvertices[rtriangles[i][1]].y - rvertices[rtriangles[i][0]].y;
	v1z = rvertices[rtriangles[i][1]].z - rvertices[rtriangles[i][0]].z;
     	l1 = sqrt( (v1x*v1x) + (v1y*v1y) + (v1z*v1z) );

	v2x = rvertices[rtriangles[i][1]].x - rvertices[rtriangles[i][0]].x;
	v2y = rvertices[rtriangles[i][1]].y - rvertices[rtriangles[i][0]].y;
	v2z = rvertices[rtriangles[i][1]].z - rvertices[rtriangles[i][0]].z;
     	l2 = sqrt( (v2x*v2x) + (v2y*v2y) + (v2z*v2z) );

	rnormals[i].x = (v1y/l1 * v2z/l2) - (v1z/l1*v2y/l2);
	rnormals[i].y = (v1z/l1 * v2x/l2) - (v1x/l1*v2z/l2);
	rnormals[i].z = (v1x/l1 * v2y/l2) - (v1y/l1*v2x/l2);

    }


  fclose (fl);
}


void bReadOff (char * filename)
/* no error checking at all - add some in if you feel inclined. */

{
  int i;

  FILE * fl = fopen (filename, "r");
  fscanf (fl, "%d %d %d\n", &numvertex, &bnumface, &numedge);

  bvertices = (Vertex *) malloc (sizeof (Vertex) * numvertex);
  btriangles = (Triangle *) malloc (sizeof (Triangle) * bnumface);
  for (i = 0; i < numvertex; i++)
    fscanf (fl, "%f %f %f\n",
        &(bvertices[i].x),
        &(bvertices[i].y),
        &(bvertices[i].z));
  for (i = 0; i < bnumface; i++)
    fscanf (fl, "3 %d %d %d\n",
        &(btriangles[i][0]),
        &(btriangles[i][1]),
        &(btriangles[i][2]));

  fclose (fl);
}


void readimage ()
/* read in an image from a PPM file, without any comments. The header
   should be of the form: P6 - X Y - 255.
   No error checks for code simplicity.
*/

{
  FILE * ppmfile = fopen ("fifa.ppm", "r");
  fscanf (ppmfile, "P6\n%d %d\n255\n", &imagewidth, &imageheight);
  image = (GLubyte *) malloc (sizeof (GLubyte) * imagewidth * imageheight * 3);
  fread (image, imagewidth * 3, imageheight, ppmfile);
  fclose (ppmfile);
}

void readimage2 ()
/* read in an image from a PPM file, without any comments. The header
   should be of the form: P6 - X Y - 255.
   No error checks for code simplicity.
*/

{
  FILE * ppmfile2 = fopen ("scene.ppm", "r");
  fscanf (ppmfile2, "P6\n%d %d\n255\n", &image2width, &image2height);
  image2 = (GLubyte *) malloc (sizeof (GLubyte) * image2width * image2height * 3);
  fread (image2, image2width * 3, image2height, ppmfile2);
  fclose (ppmfile2);
}


void Key (unsigned char key, int x, int y)
{
    switch (key)
      {
        case '+' :
          //angle -= 1.0;
          break;
        case '-' :
	  //angle += 1.0;
          break;

        case ' ' :
	  posx -= 0.5 * sin (xangle * PI / 180.0);
	  posy += 0.5 * cos (xangle * PI / 180.0);
	  break;
        case 'b' :
	case 'B' :
	  posx += 0.5 * sin (xangle * PI / 180.0);
	  posy -= 0.5 * cos (xangle * PI / 180.0);
  	break;

	case 'q' :
	case 'Q' :
	  exit(1);
	  break;
      }
}

void Mouse(int button, int state, int x, int y)
{
    switch (button)
      {
        case  GLUT_LEFT_BUTTON:
          //angle -= 1.0;
	  lastx=x; lasty=y; firstx=x;
	  if(state == GLUT_DOWN){ forward = TRUE; }
		else{ forward = FALSE; distance = 0; distancechange = 0; }
          break;
        case  GLUT_RIGHT_BUTTON :
	  //angle += 1.0;
	  lastx=x; lasty=y;
	  if(state == GLUT_DOWN){ backward = TRUE; }
		else{ backward = FALSE; distance = 0; distancechange = 0; }
          break;
	case  GLUT_MIDDLE_BUTTON:
	  exit(1);
	  break;
    }

}

void MouseMove(int x, int y)
{

distancechange = x-firstx - distance;
distance = x-firstx;

}

void drawField()
{

  glBindTexture(GL_TEXTURE_2D, texNames[0]);

  glEnable(GL_TEXTURE_2D);
  glBegin(GL_QUADS);
    glColor3f(1.0,1.0,1.0);
    glNormal3i (0.0, 0.0, -1.0);
    glTexCoord2f(1.0,1.0);
    glVertex3f( 5.0, 10.0, -100.0);
    glTexCoord2f(0.0,1.0);
    glVertex3f( -5.0, 10.0, -100.0);
    glTexCoord2f(0.0,0.0);
    glVertex3f( -5.0, 20.0, -100.0);
    glTexCoord2f(1.0,0.0);
    glVertex3f( 5.0, 20.0, -100.0);	// backwall pic
  glEnd();
  glDisable(GL_TEXTURE_2D);

  glBegin (GL_QUADS);



    glColor3f(0.527,0.371,0.063);
    glNormal3i (0.0, 0.0, -1.0);
    glVertex3f( 30.0, 0.0, -100.1);
    glVertex3f( -20.0, 0.0, -100.1);
    glVertex3f( -20.0, 25.0, -100.1);
    glVertex3f( 30.0, 25.0, -100.1);	// backwall

    glColor3f(0.527,0.371,0.063);
    glNormal3i (0.0, 0.0, -1.0);
    glVertex3f( 30.0, 0.0, 0.0);
    glVertex3f( -20.0, 0.0, 0.0);
    glVertex3f( -20.0, 25.0, 0.0);
    glVertex3f( 30.0, 25.0, 0.0);	// nearwall

    //glColor3f(0.746,0.023,0.023);  //too red
    glColor3f(0.555,0.043,0.043);
    glNormal3i (0.0,0.0,0.0);
    glVertex3f( -20.0, 0.0, 0.1);
    glVertex3f( -20.0, 0.0, -100.1);
    glVertex3f( -20.0, 25.0, -100.1);
    glVertex3f( -20.0, 25.0, 0.1);	// leftwall

    glColor3f(0.3,0.6,0.3);
    glNormal3i (0.0, -1.0, 0.0);
    glVertex3f( 20.0, 0.0, 0.0);
    glVertex3f( -20.0, 0.0, 0.0);
    glVertex3f( -20.0, 0.0, -100.1);
    glVertex3f( 20.0, 0.0, -100.1);	// court

    glColor3f(1.0,1.0,1.0);
    glVertex3f( 20.0, 0.1, -49.75);
    glVertex3f( -20.0, 0.1, -49.75);
    glVertex3f( -20.0, 0.1, -50.75);
    glVertex3f( 20.0, 0.1, -50.75); 	// middle line

    glColor3f(1.0,1.0,1.0);
    glNormal3i (0.0, 1.0, 0.0);
    glVertex3f( 19.5, 0.1, 0.0);
    glVertex3f( 20.5, 0.1, 0.0);
    glVertex3f( 20.5, 0.1, -100.0);
    glVertex3f( 19.5, 0.1, -100.0); 	// right line (on the line is in)

    glColor3f(0.2,0.2,0.2);
    glNormal3i (0.0,0.0,-1.0);
    glVertex3f( 5.0, 0.0, -100.0);
    glVertex3f( -5.0, 0.0, -100.0);
    glVertex3f( -5.0, 5.0, -100.0);
    glVertex3f( 5.0, 5.0, -100.0);	// far goal

    glColor3f(0.2,0.2,0.2);
    glNormal3i (0.0,0.0,1.0);
    glVertex3f( 5.0, 0.0, -0.1);
    glVertex3f( -5.0, 0.0, -0.1);
    glVertex3f( -5.0, 5.0, -0.1);
    glVertex3f( 5.0, 5.0, -0.1);	// near goal

    glColor3f(1.0,1.0,1.0);
    glNormal3i (0.0, -1.0, 0.0);
    glVertex3f( 10.0, 0.1, 0.0);
    glVertex3f( 9.5, 0.1, 0.0);
    glVertex3f( 9.5, 0.1, -10.0);
    glVertex3f( 10.0, 0.1, -10.0);      // near right box line

    glVertex3f( 10.0, 0.1, -10.0);
    glVertex3f( 10.0, 0.1, -9.5);
    glVertex3f( -10.0, 0.1, -9.5);
    glVertex3f( -10.0, 0.1, -10.0);	// near front box line

    glVertex3f( -10.0, 0.1, -10.0);
    glVertex3f( -9.5, 0.1, -10.0);
    glVertex3f( -9.5, 0.1, 0.0);
    glVertex3f( -10.0, 0.1, 0.0);	// near left box line

    glNormal3i (0.0, 1.0, 0.0);
    glVertex3f( 10.0, 0.1, -100.0);
    glVertex3f( 9.5, 0.1, -100.0);
    glVertex3f( 9.5, 0.1, -90.0);
    glVertex3f( 10.0, 0.1, -90.0);      // far right box line

    glVertex3f( 10.0, 0.1, -90.0);
    glVertex3f( 10.0, 0.1, -90.5);
    glVertex3f( -10.0, 0.1, -90.5);
    glVertex3f( -10.0, 0.1, -90.0);	// far front box line

    glVertex3f( -10.0, 0.1, -90.0);
    glVertex3f( -9.5, 0.1, -90.0);
    glVertex3f( -9.5, 0.1, -100.0);
    glVertex3f( -10.0, 0.1, -100.0);	// far left box line

    glColor3f(0.6,0.6,0.3);
    glNormal3i (0.0, -1.0, 0.0);
    glVertex3f( 30.0, 25.0, 0.1);
    glVertex3f( -20.0, 25.0, 0.1);
    glVertex3f( -20.0, 25.0, -100.1);
    glVertex3f( 30.0, 25.0, -100.1);	// roof

  glEnd();


}


void drawOrangePenguin()
{
  int i;

  glBegin (GL_TRIANGLES);
    for (i = 0; i < pnumface; i++)
      {
	glColor3f (0.9, 0.9, 0.9);	        	
	if(i<13) { glColor3f (0.0, 0.0, 0.0);  }  	    // feet
        if(i>209 && i<215) { glColor3f (0.0, 0.0, 0.0); }   // left wing incl line to feet
	if(i>199 && i<209) { glColor3f (0.0, 0.0, 0.0); }   // right wing incl line b/w wings
	if(i>226 ) { glColor3f (0.95, 0.38, 0.05); }   	    // beak		

        glVertex3f (pvertices[ptriangles[i][0]].x,
                    pvertices[ptriangles[i][0]].y,
                    pvertices[ptriangles[i][0]].z);
        glVertex3f (pvertices[ptriangles[i][1]].x,
                    pvertices[ptriangles[i][1]].y,
                    pvertices[ptriangles[i][1]].z);
        glVertex3f (pvertices[ptriangles[i][2]].x,
                    pvertices[ptriangles[i][2]].y,
                    pvertices[ptriangles[i][2]].z);
	//glNormal3f(pnormals[i].x, pnormals[i].y, pnormals[i].z);
      }

  glEnd ();

}


void drawGreenPenguin()
{
  int i;

  glBegin (GL_TRIANGLES);
    for (i = 0; i < pnumface; i++)
      {
	
	glColor3f (0.9, 0.9, 0.9);	        	
	if(i<13) { glColor3f (0.0, 0.0, 0.0);  }  	    // feet
        if(i>209 && i<215) { glColor3f (0.0, 0.0, 0.0); }   // left wing incl line to feet
	if(i>199 && i<209) { glColor3f (0.0, 0.0, 0.0); }   // right wing incl line b/w wings
	if(i>226 ) { glColor3f (0.0, 1.0, 0.0); }   	    // beak		

        glVertex3f (pvertices[ptriangles[i][0]].x,
                    pvertices[ptriangles[i][0]].y,
                    pvertices[ptriangles[i][0]].z);
        glVertex3f (pvertices[ptriangles[i][1]].x,
                    pvertices[ptriangles[i][1]].y,
                    pvertices[ptriangles[i][1]].z);
        glVertex3f (pvertices[ptriangles[i][2]].x,
                    pvertices[ptriangles[i][2]].y,
                    pvertices[ptriangles[i][2]].z);
      }

  glEnd ();

}


void drawRocket()
{
  int i;

  glBegin (GL_TRIANGLES);
    for (i = 0; i < rnumface; i++)
      {
	
	glColor3f (0.9, 0.3, 0.3);	        	

        glVertex3f (rvertices[rtriangles[i][0]].x,
                    rvertices[rtriangles[i][0]].y,
                    rvertices[rtriangles[i][0]].z);
        glVertex3f (rvertices[rtriangles[i][1]].x,
                    rvertices[rtriangles[i][1]].y,
                    rvertices[rtriangles[i][1]].z);
        glVertex3f (rvertices[rtriangles[i][2]].x,
                    rvertices[rtriangles[i][2]].y,
                    rvertices[rtriangles[i][2]].z);
	glNormal3f(rnormals[i].x, rnormals[i].y, rnormals[i].z);
      }

  glEnd ();

}


void initLights()
{
	static float intensity = 10.0;

//	GLfloat Ambience[] = { 0.7,0.7,0.7,1.0 };		// A hint of ...grey
	GLfloat Ambience[] = { 1.0,1.0,1.0,1.0 };		// A hint of ...grey

	GLfloat ACol[] = { 1.0, 1.0, 1.0, 1.0 };		// Spot A Colour
	GLfloat ASpecIntensity[] = { 1.0, 1.0, 1.0, 1.0 };	// Specular A Red

	GLfloat BCol[] = { 1.0, 1.0, 1.0, 1.0 };		// Spot B Colour
	GLfloat BSpecIntensity[] = { 1.0, 1.0, 1.0, 1.0 };	// Specular B Red

	GLfloat CCol[] = { 1.0, 1.0, 1.0, 1.0 };		// Spot C Colour
	GLfloat CSpecIntensity[] = { 0.8, 0.0, 0.0, 1.0 };	// Specular C Red

	GLfloat DCol[] = { 1.0, 1.0, 1.0, 1.0 };		// Spot D Colour
	GLfloat DSpecIntensity[] = { 0.8, 0.0, 0.0, 1.0 };	// Specular D Red

	GLfloat ECol[] = { 1.0, 1.0, 1.0, 1.0 };		// Spot E Colour
	GLfloat ESpecIntensity[] = { 0.8, 0.0, 0.0, 1.0 };	// Specular E Red

	// Set showing backsides
        glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

	// Set local/inf viewpoint
	//glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 0.0);

	// Set ambient levels of entire scene
	//glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Ambience);
	
	// turn on the lights
	glEnable(GL_LIGHTING);

	// turn on indiv lights
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT2);
	glEnable(GL_LIGHT3);
	glEnable(GL_LIGHT4);	// rover	

	// create and position spot light
	glLightfv(GL_LIGHT0,GL_DIFFUSE,ACol);		
 	glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,intensity);		// Intensity
	glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,180.0);		// Angle
	glLightfv(GL_LIGHT0,GL_SPECULAR,ASpecIntensity); 	//Specular contribution


	// create and position spot light
	glLightfv(GL_LIGHT1,GL_DIFFUSE,BCol);		
 	glLightf(GL_LIGHT1,GL_SPOT_EXPONENT,intensity);		// Intensity
	glLightf(GL_LIGHT1,GL_SPOT_CUTOFF,10.0);		// Angle
	glLightfv(GL_LIGHT1,GL_SPECULAR,BSpecIntensity); 	//Specular contribution

	// create and position spot light
	glLightfv(GL_LIGHT2,GL_DIFFUSE,CCol);		
 	glLightf(GL_LIGHT2,GL_SPOT_EXPONENT,intensity);		// Intensity
	glLightf(GL_LIGHT2,GL_SPOT_CUTOFF,10.0);		// Angle
	glLightfv(GL_LIGHT2,GL_SPECULAR,BSpecIntensity); 	//Specular contribution

	// create and position spot light
	glLightfv(GL_LIGHT3,GL_DIFFUSE,DCol);		
 	glLightf(GL_LIGHT3,GL_SPOT_EXPONENT,intensity);		// Intensity
	glLightf(GL_LIGHT3,GL_SPOT_CUTOFF,180.0);		// Angle
	glLightfv(GL_LIGHT3,GL_SPECULAR,BSpecIntensity);	//Specular contribution

	// create and position spot light
	glLightfv(GL_LIGHT4,GL_DIFFUSE,ECol);		
 	glLightf(GL_LIGHT4,GL_SPOT_EXPONENT,intensity);		// Intensity
	glLightf(GL_LIGHT4,GL_SPOT_CUTOFF,10.0);		// Angle
	glLightfv(GL_LIGHT4,GL_SPECULAR,BSpecIntensity); 	//Specular contribution

}

void lights()
{

	GLfloat APosition[] = { 19.0, 23.0, -99.0, 1.0 };	// Spot A position
	GLfloat ADirection[] = { 15.0, 0.0, -75.0,1.0 };	// Spot A Direction
//	GLfloat APosition[] = { 0.0, 12.0, 0.0, 1.0 };		// Spot A position
//	GLfloat ADirection[] = { 0.0,0.0,-12.0, 1.0 };		// Spot A Direction
	GLfloat BPosition[] = { -19.0, 23.0, -99.0, 1.0 };	// Spot B position
	GLfloat BDirection[] = { -15.0,0.0,-75.0,1.0 };		// Spot B Direction
	GLfloat CPosition[] = { -19.0, 23.0, -1.0, 1.0 };	// Spot C position
	GLfloat CDirection[] = { -15.0,0.0,-15.0,1.0 };		// Spot C Direction
	GLfloat DPosition[] = { 19.0, 23.0, -1.0, 1.0 };	// Spot D position
	GLfloat DDirection[] = { 15.0,0.0,-15.0,1.0 };		// Spot D Direction
	GLfloat EPosition[] = { 19.0, 23.0, 50.0-ballz, 1.0 };	// Spot E position
	GLfloat EDirection[] = { ballx, 0.0, 50.0-ballz,1.0 };	// Spot E Direction

	glLightfv(GL_LIGHT0,GL_POSITION,APosition);		// Position
	glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,ADirection);	// Direction
	glLightfv(GL_LIGHT1,GL_POSITION,BPosition);		// Position
	glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,BDirection);	// Direction
	glLightfv(GL_LIGHT2,GL_POSITION,CPosition);		// Position
	glLightfv(GL_LIGHT2,GL_SPOT_DIRECTION,CDirection);	// Direction
	glLightfv(GL_LIGHT3,GL_POSITION,DPosition);		// Position
	glLightfv(GL_LIGHT3,GL_SPOT_DIRECTION,DDirection);	// Direction

}

void lightMaterial()
{
  GLfloat material_ambient[] = { 1.0, 1.0, 0.0, 1.0 };
  GLfloat material_diffuse [] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat material_specular [] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat material_emission [] = { 1.0, 1.0, 1.0, 1.0 };

  glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128.0);
  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
  glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
}

void offMaterial()
  {
    GLfloat material_emission [] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat material_diffuse [] = { 0.75, 0.75, 0.75, 1.0 };
    GLfloat material_specular [] = { 0.3, 0.3, 0.3, 1.0 };

    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
    glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 0.0);
  }


void initMaterial()
  {
    GLfloat material_emission [] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_diffuse [] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_specular [] = { 0.0, 0.0, 0.0, 1.0 };

    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
    glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 0.0);
  }


void drawBox()
{

  glBindTexture(GL_TEXTURE_2D, texNames[1]);

  glEnable(GL_TEXTURE_2D);
  glBegin(GL_QUADS);
    glColor3f(1.0,1.0,1.0);
    glNormal3i (1.0,0.0,0.0);
    glTexCoord2f(0.0,1.0);
    glVertex3f(29.5,10.0,-70.0);

    glTexCoord2f(0.0,0.0);
    glVertex3f(29.5,20.0,-70.0);

    glTexCoord2f(1.0,0.0);
    glVertex3f(29.5,20.0,-10.0);

    glTexCoord2f(1.0,1.0);
    glVertex3f(29.5,10.0,-10.0);		//sidewall
    glColor3f(1.0,1.0,1.0);
  glEnd();
  glDisable(GL_TEXTURE_2D);

  glBegin(GL_QUADS);
//   glColor3f(0.746,0.023,0.023);
   glColor3f(0.555,0.043,0.043);
   glNormal3i (1.0,0.0,0.0);
   glVertex3f(30.0,0.0,-101.0);
   glVertex3f(30.0,25.0,-101.0);
   glVertex3f(30.0,25.0,0.0);
   glVertex3f(30.0,0.0,0.0);		//sidewall
  glEnd();

  glBegin(GL_QUADS);
   glNormal3i (0.0,-1.0,0.0);
   glColor3f(0.3,0.6,0.3);
   glVertex3f(20.0,0.0,-100.1);
   glVertex3f(30.0,0.0,-100.1);
   glVertex3f(30.0,0.0,0.0);
   glVertex3f(20.0,0.0,0.0);		//sidefloor
  glEnd();

  glColor3f(0.3,0.3,0.8);

}

void drawLightSpheres()
  {
    int i;

    //ball following light
    glTranslatef (19.0,24.0,-50.0+ballz);
    glutSolidSphere(0.5,10.0,10.0);
    glTranslatef (-19.0,-24.0,50.0-ballz);

    glTranslatef (19.0,24.0,0.0);

    glutSolidSphere(0.5,10.0,10.0);

    for(i = 0; i < 18; i++)
    {
      glutSolidSphere(0.5,10.0,10.0);
      glTranslatef (-2.0,0.0,0.0);
    }

    glutSolidSphere(0.5,10.0,10.0);
    glTranslatef (0.0,0.0,-98.0);

    glutSolidSphere(0.5,10.0,10.0);
    glTranslatef (2.0,0.0,0.0);

    for(i = 0; i < 18; i++)
    {
      glutSolidSphere(0.5,10.0,10.0);
      glTranslatef (2.0,0.0,0.0);
    }

    glutSolidSphere(0.5,10.0,10.0);
    glTranslatef (-19.0,-24.0,49.0);

  }


//=================DISPLAY================================

void display ()
    
{

  int i;
  static float time = 0.0;

  static float ballmovez = 0.0;
  static float ballmovex = 0.0;
  static float ballxgoal = 0.0;
  static float ballzgoal = 0.0;
  static float xaccel = 0.0;
  static float zaccel = 0.0;

  static float p1x = -0.75;
  static float p1z = 0.0;

  static float p2x = 0.0;
  static float p2z = 15.0;
  static penguinstate p2state = WAITING;
  static penguinstate p1state = WAITING;

  static int roll = FALSE;

  // flytraps
  char * wait;
  float diffx;
  float diffz;
  char * str;

  // arbs
  float r;

  // Penguin 1 kick ball if it's close
  if(ballx-p1x<1.0 && ballx-p1x>-1.0 && p2state!=CHASING)
     {
	if(ballz-p1z<1.0 && ballz-p1z>-1.0)
	    { 	
		   // random z kick amount
		   ballmovez = rand()%(int)(-ballz+50.0);

		   // random x kick amount
		   r= 10.0*rand()/(RAND_MAX+1.0);
		   printf("\n%f",r);
		   if(r<5.0)   //kick to left
		      {
			   printf("\nShould go left");
			   ballmovex = -rand()%(int)(20.0+ballx); 						
		      }
		   else		             //kick to right
		      {
			   ballmovex = rand()%(int)(-ballx+20.0);
		      }

	 	   ballxgoal = ballx+ballmovex;
		   ballzgoal = ballz+ballmovez;
		   xaccel = (ballxgoal-p1x)/40.0;
		   zaccel = (ballzgoal-p1z)/40.0;		
		   p1state = WAITING;
		   p2state = CHASING;
	    }	
     }

  // Penguin 2 kick ball if its close
  if(ballx-p2x<1.0 && ballx-p2x>-1.0 && p1state!=CHASING)
     {
	if(ballz-p2z<1.0 && ballz-p2z>-1.0)
	    {
		   // random z kick amount
   		   ballmovez = -rand()%(int)(ballz+50.0);

		   // random x kick amount
		   //r = rand()%10;
		   r= 10.0*rand()/(RAND_MAX+1.0);
		   printf("\n%f",r);
		   if(r<5.0)   //kick to left
		      {
			   printf("\nShould go left");
			   ballmovex = -rand()%(int)(20.0+ballx); 						
		      }
		   else		             //kick to right
		      {
			   ballmovex = rand()%(int)(-ballx+20.0);
		      }

		   printf("\nPenguin 2:\n ballmovex: %f\n ballmovez: %f\n",ballmovex, ballmovez );
	 	   ballxgoal = ballx+ballmovex;
		   ballzgoal = ballz+ballmovez;
		   xaccel = (ballxgoal-p2x)/40.0;   // this needs neg check
		   zaccel = (ballzgoal-p2z)/40.0;		
		   p2state = WAITING;
		   p1state = CHASING;
		   printf(" ballxgoal: %f\n ballzgoal: %f\n",ballxgoal, ballzgoal );
  	    }
     }

  //flyswatting
  //printf("\nxaccel:%f",xaccel);
  //if(p2state==WAITING){str="waiting";} else {str="chasing";};
  //printf("\nzaccel:%f\np2state:%s\n",zaccel,str);

  if(forward)
      {
	posx -= 0.05 * sin (xangle * PI / 180.0);
	posy += 0.05 * cos (xangle * PI / 180.0);
      }

  if(backward)
      {
	posx += 0.05 * sin (xangle * PI / 180.0);
	posy -= 0.05 * cos (xangle * PI / 180.0);
      }

  xangle+=0.5*distancechange;

  glClearColor (0.0, 0.0, 1.0, 0.0);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // texture settings
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);

  glLoadIdentity();

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glFrustum (-1.0, 1.0, -1.0, 1.0, 2.0, 5000.0);

  glMatrixMode (GL_MODELVIEW);

  glRotatef (xangle, 0.0, 1.0, 0.0);
  glRotatef (yangle, 1.0, 0.0, 0.0);

  glTranslatef (posx, -HEIGHT, posy);

  //-----------------LIGHTING

  lights();

  glColor3f(1.0,1.0,1.0);

  lightMaterial();

  drawLightSpheres();


  initMaterial();

  time = time + 0.4;

    glTranslatef (0.0,0.0,50.0);	// origin back to field middle

    drawBox();

    drawField(); 	// draw the field, goals, lines, wall, roof

    glTranslatef (0.0,0.0,-50.0);	// origin back to original

    // ball position calculation
    if((ballx>0.0 && ballxgoal<0.0) || (ballx<0.0 && ballxgoal>0.0))
      {
	if(ballx-ballxgoal>1.0 || ballx-ballxgoal<-1.0){ ballx += ballmovex/40.0; }
    	if(ballz-ballzgoal>1.0 || ballz-ballzgoal<-1.0){ ballz += ballmovez/40.0; }
      }
    else	// same side of center
      {
	if(ballx-ballxgoal>1.0 || ballx-ballxgoal<-1.0){ ballx += ballmovex/40.0; }
    	if(ballz-ballzgoal>1.0 || ballz-ballzgoal<-1.0){ ballz += ballmovez/40.0; }
      }

  offMaterial();

    glTranslatef (ballx, 0.25, ballz);

    glColor3f(0.0,0.0,0.7);
    glutSolidSphere(0.25,10.0,10.0);	// draw ball

    glTranslatef (-ballx, -0.25, -ballz);

// Penguin 1 position calculation
if(p1state==CHASING)
 {
  diffx = p1x-ballx;
  diffz = p1z-ballz;
  //printf("\ncheck:\n p1x-ballx: %f\n p1z-ballz: %f\n",diffx,diffz);
  if(p1x-ballx<=1.0 && p1x-ballx>=-1.0 ) {
      if(p1z-ballz<=1.0 && p1z-ballz>=-1.0 )
	{
	  //printf("          here            ");	
	  ballx=p1x;
	  ballz=p1z;
	  p1state = WAITING;
	}

   }
  else {  p1x = p1x + (ballx-p1x)/10.0;   }

  if(p1z-ballz<=1.0 && p1z-ballz>=-1.0 )
	{
	  //hackhack
	}
  else {  p1z = p1z + (ballz-p1z)/10.0; }
 }

    glTranslatef (p1x,0.0,p1z);

    drawOrangePenguin();	// draw Penguin 1

    glTranslatef (-p1x,0.0,-p1z);

// Penguin 2 position calculation
if(p2state==CHASING)
 {
  diffx = p2x-ballx;
  diffz = p2z-ballz;
  //printf("\ncheck:\n p2x-ballx: %f\n p2z-ballz: %f\n",diffx,diffz);
  if(p2x-ballx<1.0 && p2x-ballx>-1.0 ) {
      if(p2z-ballz<1.0 && p2z-ballz>-1.0 )
	{
	  ballx=p2x;
	  ballz=p2z;
	  p2state = WAITING;
	}
   }
  else  { p2x = p2x + (ballx-p2x)/10.0; }

  if(p2z-ballz<1.0 && p2z-ballz>-1.0 )
	{
	  //hackhack
	}
  else {  p2z = p2z + (ballz-p2z)/10.0; }

 }

  glTranslatef (p2x,0.0,p2z);

  glRotatef (-180.0, 0.0, 1.0, 0.0);

  drawGreenPenguin();

  glRotatef (180.0, 0.0, 1.0, 0.0);

  glTranslatef (-p2x,0.0,-p2z);

  if(time<30)
    {
     glTranslatef (25.0,30.0-time,-45.0);
     drawRocket();
     glTranslatef (-25.0,-30.0+time,45.0);
    }
  else
    {
     glTranslatef (25.0,0.0,-45.0);
     drawRocket();
     glTranslatef (-25.0,0.0,45.0);
    }

  glTranslatef (0.0,0.0,50.0);		// origin center field  conceptual translation?

  glFlush ();
  glutSwapBuffers();

}

void SetShape (GLsizei w, GLsizei h)
    
{
  glViewport (0, 0, w, h);
  width = w;
  height = h;
}

int main (int argc, char * argv [])
    
{

  srand(1);	//set random seed

  glutInit(&argc, argv); 
  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  glutInitWindowPosition (10, 100);
  glutInitWindowSize (350, 350);
  glutCreateWindow (argv[0]);

  pReadOff ("penguin.off");
  rReadOff ("rocket.off");

  readimage();			// Read in images for texturing
  readimage2();

  glShadeModel (GL_SMOOTH);
  glEnable (GL_DEPTH_TEST);
  glEnable (GL_NORMALIZE);
  glEnable (GL_COLOR_MATERIAL);

  initMaterial();
  initLights();

  // Do texture init
  glGenTextures(2, texNames);

  glBindTexture(GL_TEXTURE_2D, texNames[0]);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, imagewidth, imageheight, 0, GL_RGB, GL_UNSIGNED_BYTE, image); //surely wrong

  glBindTexture(GL_TEXTURE_2D, texNames[1]);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, image2width, image2height, 0, GL_RGB, GL_UNSIGNED_BYTE, image2); //surely wrong


  glutReshapeFunc (SetShape);
  glutDisplayFunc (display);
  glutIdleFunc (display);
  glutKeyboardFunc (Key);
  glutMouseFunc(Mouse);
  glutMotionFunc(MouseMove);

  glutMainLoop ();
}

