#include "gl.h"
#include "glu.h" 
#include<math.h>
#include<stdio.h>
#include "tk.h"

#define PI		3.141592654
#define PINFRAME	4
#define PSPACE		60	
#define SPEED		1.0	
#define CRASHFRAMES	15
#define FRACTIONINC	10.0
#define abs(a)          ((a<0.0)? -(a) : (a))

unsigned char RTF[3] = { 0xff, 0x55, 0x55};  /* Orange */
unsigned char RBF[3] = { 0x88, 0x11, 0x11};

unsigned char BTF[3] = { 0x55, 0x55, 0xff};  /* Blue */
unsigned char BBF[3] = { 0x22, 0x22, 0x88};

unsigned char GTF[3] = { 0x77, 0xff, 0x77};  /* Green */
unsigned char GBF[3] = { 0x00, 0x99, 0x00};

unsigned char PTF[3] = { 0xff, 0x55, 0xcc};  /* Pink */
unsigned char PBF[3] = { 0x99, 0x05, 0x22};

unsigned char YTF[3] = { 0xff, 0xff, 0x33};  /* Yellow */
unsigned char YBF[3] = { 0x88, 0x88, 0x11};

unsigned char OTF[3] = { 0xdd, 0x33, 0xff};  /* Purple */
unsigned char OBF[3] = { 0x66, 0x11, 0x88};

#define BLUE	{{BTF,BTF,BTF,BTF},{BBF,BBF,BBF,BBF}}
#define GREEN	{{GTF,GTF,GTF,GTF},{GBF,GBF,GBF,GBF}}
#define RED	{{RTF,RTF,RTF,RTF},{RBF,RBF,RBF,RBF}}
#define YELLOW  {{YTF,YTF,YTF,YTF},{YBF,YBF,YBF,YBF}}
#define PURPLE	{{PTF,PTF,PTF,PTF},{PBF,PBF,PBF,PBF}}
#define ORANGE	{{OTF,OTF,OTF,OTF},{OBF,OBF,OBF,OBF}}

int random[PINFRAME];
float ztrans=0.0;
float slowdown=0.0;
int mask;
int i,j,k;
int ii;
double out;
int pleft, pright;
int shift;
int pastpannel=0, oldpastpannel=0;
float xship, yship;
int angle;
int hit=0;
int fbhit=0;
int sign;
int hitangle=0;
float xlook=0.0, ylook=0.0;
int cycle=0;
float xfb1=0.0, yfb1=20.0;
float xfb2=0.0, yfb2=20.0;
float distin, fdistx, fdisty;
float startpl[3], startpr[3], endpoint[3];
char wallcount[30];
int hitcount=0;
int wallpast=0;
int winWidth, winHeight, winX, winY;
int screenHeight, screenWidth;
int mousex, mousey;
int type;
int unit;

float identy[4][4] = { { 1.0, 0.0, 0.0, 0.0 },
		       { 0.0, 1.0, 0.0, 0.0 },
		       { 0.0, 0.0, 1.0, 0.0 },
		       { 0.0, 0.0, 0.0, 1.0 } };

int* pcolor[16][2][4] ={ BLUE,
			GREEN,
			RED,
			YELLOW,
			PURPLE,
			ORANGE,
			BLUE,
			GREEN,
			RED,
			YELLOW,
			PURPLE,
			ORANGE,
			BLUE,
			PURPLE,
			ORANGE,
			BLUE};

			
float starverts[25][3] = { { -1.0,  1.0,  1.0 },
			   { -1.0,  1.0,  0.0 }, 
			   { -1.0,  1.0, -1.0 }, 
			   {  0.0,  1.0, -1.0 }, 
			   {  1.0,  1.0, -1.0 }, 
			   {  1.0,  1.0,  0.0 }, 
			   {  1.0,  1.0,  1.0 }, 
			   {  0.0,  1.0,  1.0 }, 

			   { -1.0,  0.0,  1.0 }, 
			   { -1.0,  0.0,  0.0 }, 
			   { -1.0,  0.0, -1.0 }, 
			   {  0.0,  0.0, -1.0 }, 
			   {  1.0,  0.0, -1.0 }, 
			   {  1.0,  0.0,  0.0 }, 
			   {  1.0,  0.0,  1.0 }, 
			   {  0.0,  0.0,  1.0 }, 

			   { -1.0, -1.0,  1.0 }, 
			   { -1.0, -1.0,  0.0 }, 
			   { -1.0, -1.0, -1.0 }, 
			   {  0.0, -1.0, -1.0 }, 
			   {  1.0, -1.0, -1.0 }, 
			   {  1.0, -1.0,  0.0 }, 
			   {  1.0, -1.0,  1.0 },
			   {  0.0, -1.0,  1.0 },

			   {  0.0,  0.0,  0.0 } };




float verts[40][3] = { {  0.0, 40.0,  0.0},
                       { 15.0, 40.0,  0.0},
                       { 30.0, 40.0,  0.0},
                       {  0.0, 30.0,  0.0},
                       { 15.0, 30.0,  0.0},
                       { 30.0, 30.0,  0.0},
                       {  0.0, 20.0,  0.0},
                       { 15.0, 20.0,  0.0},
                       { 30.0, 20.0,  0.0},
                       {  0.0, 10.0,  0.0},
                       { 15.0, 10.0,  0.0},
                       { 30.0, 10.0,  0.0},
                       {  0.0,  0.0,  0.0},
                       { 15.0,  0.0,  0.0},
                       { 30.0,  0.0,  0.0},
                       {  0.0, 35.0,  5.0},
                       {  0.0, 35.0, -5.0},
                       { 15.0, 35.0,  5.0},
                       { 15.0, 35.0, -5.0},
                       { 30.0, 35.0,  5.0},
                       { 30.0, 35.0, -5.0},
                       {  0.0, 25.0,  5.0},
                       {  0.0, 25.0, -5.0},
                       { 15.0, 25.0,  5.0},
                       { 15.0, 25.0, -5.0},
                       { 30.0, 25.0,  5.0},
                       { 30.0, 25.0, -5.0},
                       {  0.0, 15.0,  5.0},
                       {  0.0, 15.0, -5.0},
                       { 15.0, 15.0,  5.0},
                       { 15.0, 15.0, -5.0},
                       { 30.0, 15.0,  5.0},
                       { 30.0, 15.0, -5.0},
                       {  0.0,  5.0,  5.0},
                       {  0.0,  5.0, -5.0},
                       { 15.0,  5.0,  5.0},
                       { 15.0,  5.0, -5.0},
                       { 30.0,  5.0,  5.0},
                       { 30.0,  5.0, -5.0} };

int panel[8][2][4] = { { {1, 16, 18, 2},
                         {16, 4, 5, 18} },

                       { {2, 18, 20, 3},
                         {18, 5, 6, 20} },

                       { {4, 22, 24, 5},
                         {22, 7, 8, 24} },

                       { {5, 24, 26, 6},
                         {24, 8, 9, 26} },

                       { {7, 28, 30, 8},
                         {28, 10, 11, 30} },

                       { {8, 30, 32, 9},
                         {30, 11, 12, 32} },

                       { {10, 34, 36, 11},
                         {34, 13, 14, 36} },

                       { {11, 36, 38, 12},
                         {36, 14, 15, 38} } };

int ends[4][4] =  { {2, 18, 5, 19},
                    {5, 24, 8, 25},
                    {8, 30, 11, 31},
                    {11, 36, 14, 37} };


int panconfig[16] = { 0x3C,
 		     0xC3,
		     0x33,
		     0xCC,
		     0x55,
		     0xAA,
		     0xFC,
		     0x3F, 
		     0x7F,
		     0xBF,
		     0xDF,
		     0xEF,
		     0xF7,
		     0xFB,
		     0xFD,
		     0xFE };

float tverts[8][3] = { { -15.0,  0.0, 0.0 },
                       {  15.0,  0.0, 0.0 },
                       { -15.0, 40.0, 0.0 },
                       {  15.0, 40.0, 0.0 },
                       { -15.0,  0.0, -PINFRAME*PSPACE },
                       {  15.0,  0.0, -PINFRAME*PSPACE },
                       { -15.0, 40.0, -PINFRAME*PSPACE },
                       {  15.0, 40.0, -PINFRAME*PSPACE } };

int             tunnel[4][2] = {{0, 4},
        {1, 5},
        {2, 6},
        {3, 7}};

/* For solids 
int tunnel[3][4] = { { 0, 2, 6, 4 },
		     { 0, 4, 5, 1 },
		     { 1, 5, 7, 3 } }; 
*/
 
void
blookat(float vx, float vy, float vz, float px, float py, float pz, int twist)
{
  float           sino, hyp, hyp1, dx, dy, dz, ftwist;

  ftwist = -twist / 10.0;
  sino = sin(ftwist * PI / 180.0);
  glRotatef(ftwist, 0.0, 0.0, 1.0);

  dx = px - vx;
  dy = py - vy;
  dz = pz - vz;

  hyp = dx * dx + dz * dz;/* hyp squared  */
  hyp1 = sqrt((double) (dy * dy + hyp));
  hyp = sqrt((double) hyp);  /* the real hyp */

  if (hyp1 != 0.0) {  /* rotate X     */
    sino = -dy / hyp1;
  } else {
    sino = 0.0;
  }

  glRotatef(asin(sino) * 180 / PI, 1.0, 0.0, 0.0);

  if (hyp != 0.0) {  /* rotate Y     */
    sino = dx / hyp;
  } else {
    sino = 0.0;
  }

  glRotatef(asin(sino) * 180.0 / PI, 0.0, 1.0, 0.0);
  glTranslatef(-vx, -vy, -vz);
}


void main(int argc, char **argv)
{
    GLenum type;

    screenHeight = 1024;
    screenWidth  = 1280;
    winWidth = 500;
    winHeight = 400;
    winX = 100;
    winY = 100;
    tkInitPosition(winX, winY, winWidth, winHeight);

    type = TK_DEPTH;
    type |= TK_RGB;
    type |= TK_DOUBLE;
    type |= TK_DIRECT;
    tkInitDisplayMode(type);

    if (tkInitWindow("Wave Demo") == GL_FALSE) {
	tkQuit();
    }

    Init();

    tkExposeFunc(DrawIt);
    tkIdleFunc(DrawIt);
    tkExec();
}

Init()
{
  glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glDisable(GL_DITHER);
  glShadeModel(GL_FLAT);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0, 1.25, 0.1, 1500.0);

  for(i=0;i<PINFRAME;++i)
    random[i] = 16*rand()/((int) pow(2,15)-1);	
}

/*
while(!getbutton(MIDDLEMOUSE))
*/
/* START of DRAW */
DrawIt()
{
	glPushMatrix();
	oldpastpannel = pastpannel;
	pastpannel = -((int) ztrans)/PSPACE;
	if(oldpastpannel != pastpannel)
	   {
	   hit = (panconfig[random[0]]&(1<<((3-((int) yship)/10)*2+(xship>0.0))))>0;
	   if(!hit)
		{
	        for(i=0;i<PINFRAME-1;++i)
		   random[i] = random[i+1];
                random[PINFRAME-1] = 16*rand()/((int) pow(2,15)-1);	
		++wallpast;
		}
	   else
	   	hitcount += 2;
	   xfb2 = xfb1;
	   yfb2 = yfb1;
	   if((int) (xship/abs(xship))+1)
	   	xfb1 = -15.0;
	   else
	   	xfb1 =  15.0;
	   yfb1 = 20.0;
	   }
	distin = -ztrans - ((float) pastpannel)*PSPACE;

	if((distin > PSPACE/2.0 - 1.0) && (distin < PSPACE/2.0 + 1.0))
		{
		fdistx = abs(xship - xfb2);
		fdisty = abs(yship - yfb2);
		if((fdistx < 2.0) && (fdisty < 2.0)) 
			{
			fbhit = 1;
	     		hitcount += 1;
			}
		}	

	if(hit || fbhit)
	   {
           unit = winWidth/100;
/*
	   glRecti(unit*10, unit, unit*10+hitcount*unit, unit*3);
	   if((unit*10+hitcount*unit) > winWidth-unit) 
*/
           if (hitcount > CRASHFRAMES)
		{
		glClearColor(1.0, 0.0, 0.0, 1.0);
		glClear(GL_COLOR_BUFFER_BIT);
		tkSwapBuffers();
		glClearColor(1.0, 1.0, 0.0, 1.0);
		glClear(GL_COLOR_BUFFER_BIT);
		for(i=0;i<50;++i) tkSwapBuffers();
		printf("Total walls past = %d\n", wallpast);
		exit(0);
		}
           glClearColor(0.0, 0.0, 0.0, 1.0);
	   glPopMatrix();
	   }
	if(hit)
	   {
	   sign = ((int) (xship/abs(xship)));
	   hitangle = sign*random[(++cycle)%4]*150;		
	   xlook = (float) sign*random[(++cycle)%4]*7;
	   ylook = (float) sign*random[(++cycle)%4]*7;
	   ztrans += 0.75*PSPACE;
	   glClearColor(1.0, 0.0, 0.0, 1.0);
           glClear(GL_COLOR_BUFFER_BIT);
	   tkSwapBuffers();
           glClear(GL_COLOR_BUFFER_BIT);
	   tkSwapBuffers();
	   glClearColor(0.0, 0.0, 0.0, 1.0);
	   hit=0;
	   fbhit=0;
	   slowdown = (((float) pastpannel)/FRACTIONINC)/1.2;
	   }
	else
	   {
	   if(fbhit)
	     {
	     sign = ((int) (xship/abs(xship)));
	     hitangle = sign*random[(++cycle)%4]*100;		
	     xlook = (float) sign*random[(++cycle)%4]*5;
	     ylook = (float) sign*random[(++cycle)%4]*5;
	     fbhit=0;
	     slowdown = (((float) pastpannel)/FRACTIONINC)/2.2;
	     ztrans -= (SPEED+(((float) pastpannel)/FRACTIONINC)-slowdown);
	     }
	   else
	     {
/* MOUSE stuff here */
            tkGetMouseLoc(&mousex, &mousey);
            xship = (float)mousex/36.8-14.0;
            yship = (float)mousey/20.25+1.0;
/*
	     xship = ((float) getvaluator(MOUSEX))/46.0-14.0;
	     yship = ((float) getvaluator(MOUSEY))/27.0+1.0;
*/
	     angle = ((int) xship)*10;
	     slowdown /= 1.005;
	     ztrans -= (SPEED+(((float) pastpannel)/FRACTIONINC)-slowdown);
	     }
	   }

	hitangle*=0.95;
	xlook*=0.95;
	ylook*=0.95;

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
	blookat(xship,yship,ztrans,xlook,20.0+ylook,-PSPACE+ztrans,angle+hitangle);

        glPushMatrix();
	glClearColor(0.0,0.0,0.0,1.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glTranslatef(0.0, 0.0, ztrans);
	
	/****** Render Tunnel ***********************************/

/*
	glBegin(GL_QUADS);
	for(i=0;i<3;++i)
	   { 
	   glColor3ub(i*80+50,i*80+50,i*80+50);
		for(j=0;j<4;++j)
		   glVertex3fv(tverts[tunnel[i][j]]);
           }
	glEnd();
	glPopMatrix();
*/
        glColor3ub(255, 255, 255);
        glBegin(GL_LINES);
        for (i = 0; i < 4; ++i) {
            for (j = 0; j < 2; ++j)
                glVertex3fv(tverts[tunnel[i][j]]);
         }
         glEnd();
    glPopMatrix();


	/****** Render Walls ***********************************/

	for(shift=PINFRAME-1; shift>=0; --shift)
	  {
          glPushMatrix();
	  glTranslatef(-15.0, 0.0, -((float) shift)*PSPACE-((float)pastpannel)*PSPACE-PSPACE);

	  /***** Render Ice Ball **********************************/

	  if(shift==0)
		{
		glShadeModel(GL_SMOOTH);
	  	glPushMatrix();
/*
  	  	glLineWidth(5.0);
*/
  	  	glLineWidth(3.0);
	  	xfb1 += (xship - xfb1)/8.0;
		yfb1 += (yship - yfb1)/8.0;
	  	glTranslatef(xfb1+15.0, yfb1, -PSPACE/2.0);
                glRotatef(ztrans * 2.0, 0.0, 1.0, 0.0);
		glScalef(2.0, 2.0, 2.0);
		glBegin(GL_LINES);
		for(i=0;i<23;++i)
		    {
		    glColor3ub(0, 255, 255);
		    glVertex3fv(starverts[24]);		
		    glColor3ub(255, 255, 255);
		    glVertex3fv(starverts[i]);		
		    }
		glEnd();
		glLineWidth(1.0);
		glPopMatrix();
		glShadeModel(GL_FLAT);
		}
          /****** Render Ends ***********************************/

	  mask = 1;
	  glBegin(GL_QUADS); 
          for(i=0;i<4;++i)
		{
		pleft = mask & panconfig[random[shift]];
		pright = (mask<<1) & panconfig[random[shift]];
		if((pleft && !pright)||(!pleft && pright))
			{
			glColor3ubv(pcolor[random[shift]][1][1]);
			for(k=0;k<4;++k)
		  	    glVertex3fv(verts[ends[i][k]-1]);
			}
		mask = mask << 2;
		}

          /****** Render Pannels ***********************************/

	  mask = 1;
          for(i=0;i<8;++i)
		{
		if(mask & panconfig[random[shift]])
			{
			for(j=0;j<2;++j)
				{
				for(k=0;k<4;++k)
				  {
				    glColor3ubv(pcolor[random[shift]][j][k]);
			  	    glVertex3fv(verts[panel[i][j][k]-1]);
				  }
				}
			}
		mask = mask << 1;
		}
          glEnd();

	  /***** Render Fire Ball **********************************/

	  if(shift==0)
		{
		glShadeModel(GL_SMOOTH);
		glPushMatrix();
/*
		glLineWidth(15.0);
*/
		glLineWidth(7.0);
		xfb2 += (xship - xfb2)/7.0;
		yfb2 += (yship - yfb2)/7.0;
		glTranslatef(xfb2+15.0, yfb2, PSPACE/2.0);
                glRotatef(ztrans * 10.0, 0.0, 1.0, 0.0);
                glRotatef(ztrans * 10.0, 1.0, 0.0, 0.0);
                glRotatef(ztrans * 10.0, 0.0, 0.0, 1.0);
                glScalef(2.0, 2.0, 2.0);
		glBegin(GL_LINES);
		for(i=0;i<23;++i)
		  {
		  glColor3ub(255, 50, 10);
		  glVertex3fv(starverts[24]);		
		  glColor3ub(255, 255, 50);
		  glVertex3fv(starverts[i]);		
		  }
		glEnd();
		glLineWidth(1.0);
		glPopMatrix();
		glShadeModel(GL_FLAT);
		}
          glPopMatrix();
          }
	tkSwapBuffers();
        glPopMatrix();
}
