#include "cs148.h"

// Screen size
int screenWidth = 640;
int screenHeight = 480;

// Mouse viewing rotation points
const double PI = 3.1415926;
const double DEG_TO_RAD = PI / 180.;
double mouse_theta = 0.;

// Mouse rotation
const double ROTATE_RATE = 0.75;
const double RADIUS = 3.;
int mouse_lastx, mouse_lasty;

// Quadric choice
const int MAX_RENDER = 5;
int render = 0;


// Mouse function -- on entry:
//   button = GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, or GLUT_RIGHT_BUTTON
//   state =  GLUT_UP or GLUT_DOWN
//   x, y = mouse location
void myMouse(int button, int state, int mousex, int mousey) {
  int x = mousex;
  int y = screenHeight - mousey;

  if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) {
    mouse_lastx = x;
    mouse_lasty = y;
  }

  if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) {
    render++;
    if (render >= MAX_RENDER)
      render = 0;
    mouse_lastx = x;
    mouse_lasty = y;
    glutPostRedisplay();
  }
}


void myMovedMouse(int mousex, int mousey) {
  
  int x = mousex;
  int y = screenHeight - mousey;

  // Update rotation 
  mouse_theta -= (double)(x - mouse_lastx) * ROTATE_RATE;
  mouse_lastx = x;
  mouse_lasty = y;
  
  // Recompute lookat (polar coords)
  double ex, ey;
  ex = RADIUS * cos(DEG_TO_RAD * mouse_theta); 
  ey = RADIUS * sin(DEG_TO_RAD * mouse_theta); 
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  // Place light
  GLfloat position[] = { 1.0, 2.0, 3.5, 1.0 };
  glLightfv(GL_LIGHT0, GL_POSITION, position);
  glEnable(GL_LIGHT0);

  // Apply viewing transform
  gluLookAt(ey, 3., ex, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  // Redraw
  glutPostRedisplay();
}


// Display function -- called to redraw window (blank, for now)
void myDisplay(void) {
  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Draw sphere with many rendering setups
  GLUquadricObj *quad;
  quad = gluNewQuadric();
  glColor3f(0., 0., 0.);
  switch (render) {
  case 0:  // Wireframe
    glDisable(GL_LIGHTING);
    gluQuadricDrawStyle(quad, GLU_LINE);
    gluSphere(quad, 1., 10, 10);
    break;
  case 1:  // Hidden lines
    glDisable(GL_LIGHTING);
    glColor3f(1., 1., 1.);
    gluQuadricDrawStyle(quad, GLU_FILL);
    gluSphere(quad, 1., 10, 10);
    glColor3f(0., 0., 0.);
    gluQuadricDrawStyle(quad, GLU_LINE);
    gluSphere(quad, 1.01, 10, 10);
    break;
  case 2:  // Filled
    glDisable(GL_LIGHTING);
    gluQuadricDrawStyle(quad, GLU_FILL);
    gluSphere(quad, 1., 10, 10);
    break;
  case 3:  // Flat shading
    gluQuadricOrientation(quad, GLU_OUTSIDE);
    gluQuadricNormals(quad, GLU_FLAT);
    glShadeModel(GL_FLAT);
    glEnable(GL_LIGHTING);
    gluSphere(quad, 1., 10, 10);
    break;
  case 4:  // Smooth shading
    gluQuadricOrientation(quad, GLU_OUTSIDE);
    gluQuadricNormals(quad, GLU_SMOOTH);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    gluSphere(quad, 1., 10, 10);
    break;
  };
  gluDeleteQuadric(quad);

  glutSwapBuffers();
}


// Reshape function -- called whenever window size changes
//   w, h = new window size
void myReshape(int w, int h) {
  screenWidth = w;
  screenHeight = h;
  glViewport(0, 0, screenWidth, screenHeight);  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (GLdouble)screenWidth / (GLdouble)screenHeight, 1.0, 10.);
  glMatrixMode(GL_MODELVIEW);
} 


// Initialization code
void myInit(void) {
  glLineWidth(2.);
  glEnable(GL_DEPTH_TEST);
  glClearColor(1.0, 1.0, 1.0, 0.0);
  mouse_lastx = 0;
  mouse_lasty = screenHeight;
  myMovedMouse(0, 0);
}


// Main function
int main(int argc, char** argv) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
  glutInitWindowSize(screenWidth, screenHeight);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("Rendering styles");
  glutDisplayFunc(myDisplay);
  glutReshapeFunc(myReshape);
  glutMouseFunc(myMouse);
  glutMotionFunc(myMovedMouse);
  myInit();
  glutMainLoop();
  return 0;
}




