/**************************************************
 *   File:     CGWorld.cpp
 *   Author:   Dr. Dalton R. Hunkins     
 *   Date:     February 2009
**************************************************/
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/Utils/MathFunctions.h>

#include "CGWorld.h"

#include <cmath>
using std::sqrt;

  CGWorld::CGWorld() {
  }
    void CGWorld::createSubWindow(int parentHandle,
                                 int parentWidth, int parentHeight,
                                 int startX,      int startY,
                                 int width,        int height) {
      windowHandle = glutCreateSubWindow(parentHandle,
                                         startX*parentWidth/100, startY*parentHeight/100,
                                         width*parentWidth/100,  height*parentHeight/100);
      CGWorld::cornerX = startX;
      CGWorld::cornerY = startY;
      CGWorld::width   = width;
      CGWorld::height  = height;                                                                              
  }

  void CGWorld::init(float clearColor[]) { 
	glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0);

	glEnable(GL_DEPTH_TEST);

	model = NULL;
     
	lightColor[0] = lightColor[1] = lightColor[2] = 0.5;
	 
	updatedAngleX = 0.0;
	updatedAngleY = 0.0;
	currentAngleX = 0.0;
	currentAngleY = 0.0;

	dragging = false;
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0, 1.0, 3.0,    // eyePoint
                0.0, 0.0, 0.0,    // lookAtPoint
                0.0, 1.0, 0.0);   // upVector
               
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, 1.0, 0.1, 100.0);
  }
  
  void CGWorld::display() {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      setLighting();

      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glRotated(updatedAngleX, 1.0, 0.0, 0.0);
      glRotated(updatedAngleY, 0.0, 1.0, 0.0);
      if (model != NULL)
         model->drawModel();    
      glPopMatrix();

      glutSwapBuffers();
  }

  void CGWorld::reshape(int width, int height) {
       deviceWindowWidth  = width;
       deviceWindowHeight = height;
       glViewport(0, 0, width, height);
  }
  
  void CGWorld::setLighting() {
	float directionalPosition[] = { 0.0, 1.0, 3.0, 0.0};

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, darkGray);

	glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor);
	glLightfv(GL_LIGHT1, GL_POSITION, directionalPosition);

	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHTING);	 
  }

  void CGWorld::setModel(ObjModel *model) {
     CGWorld::model = model;
     glutSetWindow(windowHandle);
     glutPostRedisplay();
  }     
  
  void CGWorld::mouse(int button, int state, int x, int y) {
  	 if (button == GLUT_LEFT_BUTTON)
        if (state == GLUT_DOWN) {
            startX = x;
            startY = y;
            dragging = true;
        }            
        else {
          dragging = false;
          currentAngleX = updatedAngleX;
          currentAngleY = updatedAngleY;
        }
  }
  
  void CGWorld::mouseMotion(int x, int y) {
      if (dragging) {
        double percentChangeX = (double) (x - startX) / deviceWindowWidth;
        double percentChangeY = (double) (y - startY) / deviceWindowHeight;
        updatedAngleX = currentAngleX + percentChangeY*90.0;
        updatedAngleY = currentAngleY + percentChangeX*360.0;
        if (updatedAngleX < -90.0)
           updatedAngleX = -90.0;
        if (updatedAngleX > 90.0)
           updatedAngleX = 90.0;   
	  glutSetWindow(windowHandle);
	  glutPostRedisplay();		
      }         
  } 	 	 
  
  void CGWorld::specialKeyboard(int key, int x, int y) {
      switch (key) {
         case GLUT_KEY_UP :
			float c = lightColor[0];
			c += 0.01;;
			if (c > 1.0)
				c = 1.0f;
			lightColor[0] = lightColor[1] = lightColor[2] = c;
			setLighting();
			glutSetWindow(windowHandle);
			glutPostRedisplay();
			break;
	     case GLUT_KEY_DOWN :
			c = lightColor[0];
			c -= 0.01;;
			if (c < 0.0)
				c = 0.0f;
			lightColor[0] = lightColor[1] = lightColor[2] = c;
			setLighting();
			glutSetWindow(windowHandle);
			glutPostRedisplay();
  	 	      break;
  	    } 	   
  }	
  
  int CGWorld::getWindowHandle() {
   	  return windowHandle;
  }
  
  int CGWorld::getCornerX() {
  	  return cornerX;
  }
  
  int CGWorld::getCornerY() {
  	  return cornerY;
  }
  
  int CGWorld::getWidth() {
  	  return width;
  }
  
  int CGWorld::getHeight() {
  	  return height;
  }