#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>


#ifndef NDEBUG
static void EC(void)
{
  GLenum e=glGetError();                             
  if (e){                                           
    fprintf(stderr,"%s %d error %d %s\n",          
	    __FILE__,__LINE__,e,gluErrorString(e));
    abort();
  }         
}
#else
#define EC()
#endif



#ifndef M_PI
#define M_PI 3.1415926535
#endif







int SCREEN_WIDTH=640;
int SCREEN_HEIGHT=480;
static int win=0;
static float alpha=0;
static float beta=0;

void my_keyboard_func ( unsigned char key, int x, int y )
{
}

void my_keyboard_up_func ( unsigned char key, int x, int y )
{
  if (key == 'q' ||key == 'Q' || key == 27)
    exit(0);
}
 
static int left_key=0;
static int right_key=0;
static int up_key=0;
static int down_key=0;
void my_special_func ( int special_key, int x, int y )
{
  if (special_key == GLUT_KEY_LEFT)
    left_key=1;
  else if (special_key == GLUT_KEY_RIGHT)
    right_key=1;
  else if (special_key == GLUT_KEY_UP)
    up_key=1;
  else if (special_key == GLUT_KEY_DOWN)
    down_key=1;
}

void my_special_up_func ( int special_key, int x, int y )
{
  if (special_key == GLUT_KEY_LEFT)
    left_key=0;
  else if (special_key == GLUT_KEY_RIGHT)
    right_key=0;
  else if (special_key == GLUT_KEY_UP)
    up_key=0;
  else if (special_key == GLUT_KEY_DOWN)
    down_key=0;
}


void idle_func(void)
{
  if (left_key)
    alpha += 0.02;
  if (right_key)
    alpha -=0.02;
  if (down_key)
    beta -= 0.02;
  if (up_key)
    beta += 0.02;
  glutPostRedisplay () ;  
} 



static void reshape_t(int width, int height)
{
  if (width>800)
    width=800;
  if (height>600)
    height=600;
  SCREEN_WIDTH=width;
  SCREEN_HEIGHT=height;

  glViewport(0,0,(GLint)width,(GLint)height);
  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();
  gluPerspective(60.0,width/(float)height,0.2,30.0);

  glMatrixMode(GL_MODELVIEW);

}




static void redraw(void)
{
  glShadeModel(GL_SMOOTH);
  glEnable(GL_DEPTH_TEST);
  EC();
  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);
  glFrontFace(GL_CCW);


  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(2*sin(alpha)*cos(beta),1+2*sin(beta),
	    2*cos(alpha)*cos(beta),
	    0,1,0,
	    0,1,0);
  glColor4f(0.8,0.8,0.8,0.8);
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

  glClearColor(0.2,0.2,0.2,1.0);


  glBegin(GL_LINE_LOOP);
  glVertex3f(1,0,0);
  glVertex3f(1,1,0);
  glVertex3f(-1,1,0);
  glVertex3f(-1,0,0);
  glEnd();

  glutSwapBuffers();
}


int main(int ac,char **av)
{
  freopen("ex4.log","w",stderr);
  setbuf(stderr,0);
  glutInitWindowPosition(0,0);
  glutInitWindowSize(SCREEN_WIDTH,SCREEN_HEIGHT);
  glutInit(&ac,av);
  glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
  if(!(win=glutCreateWindow("T"))) {
    fprintf(stderr,"Error opening a window.\n");
    exit(-1);
  }

  EC();
  reshape_t(SCREEN_WIDTH,SCREEN_HEIGHT);

  EC();
  glutDisplayFunc(redraw);
  glutReshapeFunc(reshape_t);
  glutIdleFunc(idle_func);
  glutKeyboardFunc ( my_keyboard_func ) ;
  glutKeyboardUpFunc ( my_keyboard_up_func ) ;
  glutSpecialFunc  ( my_special_func  ) ;
  glutSpecialUpFunc  ( my_special_up_func  ) ;


  
  glutMainLoop();
  

  return 0;
}

