#include "cs148.h"
#include "tga.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.0;
int last_mouse_valid = 0;
int mouse_lastx, mouse_lasty;
double mouse_theta = 90.0;

// Which button is being dragged right now?
int dragging = -1;

// Mouse rotation
const double ROTATE_RATE = 0.75;
const double ZOOM_RATE = 0.05;

// Where is our camera?
float ex=0, ey=1.0, ez=10.0;
  
// The texture we'll bind to the car
unsigned int carTexture = 0;

// Draw cylinder along z axis centered at origin
void DrawCylinder(double radius, double height) {

  GLUquadricObj *quad;
  glPushMatrix();
  quad = gluNewQuadric();
  glTranslated(0., 0., -height * .5);
  gluQuadricDrawStyle(quad, GLU_FILL);
  gluQuadricOrientation(quad, GLU_OUTSIDE);
  gluQuadricNormals(quad, GLU_SMOOTH);
  gluQuadricTexture(quad, GL_TRUE);
  gluCylinder(quad, radius, radius, height, 20, 10);
  glRotated(180., 1., 0., 0.);
  gluDisk(quad, 0., radius, 20, 10);
  glTranslated(0., 0., -height);
  glRotated(180., 1., 0., 0.);
  gluDisk(quad, 0., radius, 20, 10);
  gluDeleteQuadric(quad);
  glPopMatrix();

}


void myMouse(int button, int state, int mousex, int mousey) {

  int x = mousex;
  int y = screenHeight - mousey;

  // If this is the first time myMouse was called...
  if (last_mouse_valid == 0) {
    last_mouse_valid = 1;
    mouse_lastx = x;
    mouse_lasty = y;
  }

  // Record which button was pressed
  if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) {
    mouse_lastx = x;
    mouse_lasty = y;
    dragging = GLUT_LEFT_BUTTON;
  }

  else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) {
    mouse_lastx = x;
    mouse_lasty = y;
    dragging = GLUT_RIGHT_BUTTON;
  }

  else dragging = -1;

}


void myMovedMouse(int mousex, int mousey) {
  
  int x = mousex;
  int y = screenHeight - mousey;

  if (dragging == GLUT_LEFT_BUTTON) {
  
    // Update rotation 
    mouse_theta -= (double)(x - mouse_lastx) * ROTATE_RATE;
    mouse_lastx = x;
    mouse_lasty = y;
  
    // Recompute look position (polar coords)
    double radius = sqrt(ez*ez+ex*ex);
    ex = radius * cos(DEG_TO_RAD * mouse_theta); 
    ez = radius * sin(DEG_TO_RAD * mouse_theta);   

  }

  else if (dragging == GLUT_RIGHT_BUTTON) {

    // Move in or out along our current look axis
    int dy = y - mouse_lasty;
    mouse_lastx = x;
    mouse_lasty = y;
    ex += ((float)dy) * ex / 100.0;
    ey += ((float)dy) * ey / 100.0;
    ez += ((float)dy) * ez / 100.0;
    
  }

  // Redraw
  glutPostRedisplay();

}


// Turn a light on
void lights(void){

  // The position of the light
  GLfloat position[] =  {0.0, 0.0, 3.0, 0.0};

  GLfloat color[] = {1,1,1,1};
  GLfloat acolor[] = {0.2,0.2,0.2,1};
  

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  
  glLightfv(GL_LIGHT0, GL_POSITION, position);
  glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180.0);
  glLightfv(GL_LIGHT0, GL_AMBIENT, acolor);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, color);
  glLightfv(GL_LIGHT0, GL_SPECULAR, color);

  glEnable(GL_COLOR_MATERIAL);
  glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  
}


// Display function -- called to redraw window
void myDisplay(void) {
  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glEnable(GL_COLOR_MATERIAL);  
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  // Position the camera
  gluLookAt(ex, ey, ez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  // Position the light in world-space  
  lights();
  
  glColor3f(1,0,1);
  glBegin(GL_QUADS);
    glNormal3f(0,1,0);
    glVertex3f(10,0,10);
    glVertex3f(10,0,-10);
    glVertex3f(-10,0,-10);
    glVertex3f(-10,0,10);
  glEnd();

  // A billboarded quad
  glPushMatrix();
    
    // Enable texture-mapping and bind our texture
    glEnable (GL_TEXTURE_2D);
    glBindTexture (GL_TEXTURE_2D, carTexture);
    glDisable(GL_LIGHTING);

    float modelview[16];
    glGetFloatv(GL_MODELVIEW_MATRIX,modelview);

    int j,k;
    for(k=0; k<3; k++) {
      for(j=0; j<3; j++) {
        if (k==j)
          modelview[k*4+j] = 1.0;
        else
          modelview[k*4+j] = 0.0;
      }
    }

    glLoadMatrixf(modelview);
    glColor3f(1,1,1);
    glBegin(GL_QUADS);
      glNormal3f(0,0,1);
      glTexCoord2f(1,0);
      glVertex3f(6,0.5,0);
      glTexCoord2f(1,1);
      glVertex3f(6,3,0);
      glTexCoord2f(0,1);
      glVertex3f(3,3,0);
      glTexCoord2f(0,0);
      glVertex3f(3,0.5,0);
    glEnd();
  glPopMatrix();

  // Enable texture-mapping and bind our texture
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, carTexture);

  glShadeModel(GL_SMOOTH);
  glEnable(GL_LIGHTING);
  glEnable(GL_CULL_FACE);
    
  // Draw car
  glPushMatrix();
  glTranslatef(0,0.7,0);
  glColor3f(.8, .8, .8);
  DrawCylinder(.5, 2.);
  glColor3f(.3, .3, .3);
  glPushMatrix();
  glRotated(90., 0., 1., 0.);
  glTranslated(.65, -.2, .5);
  DrawCylinder(.4, .2);
  glTranslated(0., 0., -1.);
  DrawCylinder(.4, .2);
  glTranslated(-1.3, 0., 0.);
  DrawCylinder(.4, .2);
  glTranslated(0., 0., 1.);
  DrawCylinder(.4, .2);
  glPopMatrix();
  glPopMatrix();

  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(50.0, (GLdouble)screenWidth / (GLdouble)screenHeight, 1.0, 100.);
  glMatrixMode(GL_MODELVIEW);
} 


// Initialization code
void myInit(void) {
  glLineWidth(2.);
  glEnable(GL_DEPTH_TEST);
  glClearColor(1.0, 1.0, 1.0, 0.0);

  // Get a texture id for our car
  glGenTextures(1,&carTexture);

  // Build a texture map
  int retval = loadTGA("texture.tga", carTexture, 1);
  printf("LoadTGA = %d\n", retval);

}


// 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("Patches");
  glutDisplayFunc(myDisplay);
  glutReshapeFunc(myReshape);
  glutMouseFunc(myMouse);
  glutMotionFunc(myMovedMouse);
  myInit();
  glutMainLoop();
  return 0;
}




