// Aaron Pulley
// ME 570 final project
//------------------------

#include "pumpkinwij.hpp"

#define _USE_MATH_DEFINES
#define EYE_DIST 125.0

PumpkinWij::PumpkinWij(QWidget *parent) : QGLWidget(parent)
{
   pumpkinR = 5;     // default sizes
   pumpkinDist = 3;

   shadowSize = 12;
   shadowZ = 18;
   shadowY = 0;

   viewAng = 30;
   extraAng = 0;
   xOrig = 0;
}


void PumpkinWij::mousePressEvent (QMouseEvent *event)
{
   xOrig = event->x();
}


void PumpkinWij::mouseMoveEvent (QMouseEvent *event)
{
   extraAng = (xOrig - event->x())/3;

   if((viewAng + extraAng) > 89)
   {
      extraAng = 89 - viewAng;
   }

   if((viewAng + extraAng) < -89)
   {
      extraAng = -89 - viewAng;
   }

   updateGL();
}


void PumpkinWij::mouseReleaseEvent (QMouseEvent *event)
{
   xOrig = event->x();
   viewAng += extraAng;
   extraAng = 0;

   if(viewAng > 89)
   {
      viewAng = 89;
   }

   if(viewAng < -89)
   {
      viewAng = -89;
   }

   updateGL();
}


void PumpkinWij::setDist(double d)
{
   pumpkinDist = d;
   updateGL();
}


void PumpkinWij::setDia(double d)
{
   pumpkinR = d/2;
   updateGL();
}


void PumpkinWij::setShadowSize(double s)
{
   shadowSize = s;
   updateGL();
}


void PumpkinWij::draw()
{
   // set view
   glLoadIdentity();
   gluLookAt((EYE_DIST*cos((viewAng + extraAng)*M_PI/180)), (EYE_DIST*sin((viewAng + extraAng)*M_PI/180)), 80.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);

   // surroundings
   glPushMatrix();
      double xScale = pumpkinDist + 2*pumpkinR;
      if(xScale < 30)
      {
         xScale = 30;
      }
      glScalef(xScale, 72.0, 1.0);
      glCallList(groundList);
   glPopMatrix();

   glPushMatrix();
      glScalef(0.0, 72.0, 36.0);
      glCallList(wallList);
   glPopMatrix();

   // pumpkin
   glPushMatrix();
      glTranslated((pumpkinR + pumpkinDist), 0.0, pumpkinR);
      glScalef(pumpkinR, pumpkinR, pumpkinR);
      glCallList(pumpkinList);
   glPopMatrix();

   // shadow
   glPushMatrix();
      glTranslated(0.01, shadowY, shadowZ);
      glScalef(0.0, shadowSize, shadowSize);
      glCallList(fakeList);
   glPopMatrix();
}


//almost entirely copied from Dr. Merkley's og4.cpp
void PumpkinWij::initializeGL()
{
   qglClearColor(Qt::black);

   // Light values and coordinates
   GLfloat  whiteLight[] = { 0.4f, 0.4f, 0.4f, 1.0f };
   GLfloat  diffuseLight[] = { 0.8f, 0.8f, 0.8f, 1.0f };
   GLfloat  specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
   GLfloat lightPos[] = { -100.0f, 200.0f, 50.0f, 1.0f };

   glEnable( GL_DEPTH_TEST );
   glEnable( GL_COLOR_MATERIAL);
   glEnable( GL_NORMALIZE );

   glEnable( GL_LIGHTING );
   glLightfv( GL_LIGHT0,GL_AMBIENT,whiteLight);
   glLightfv( GL_LIGHT0,GL_DIFFUSE,diffuseLight);
   glLightfv( GL_LIGHT0,GL_SPECULAR,specular);
   glLightfv( GL_LIGHT0,GL_POSITION,lightPos);
   glEnable( GL_LIGHT0 );

   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
   glMaterialfv(GL_FRONT, GL_SPECULAR,specular);
   glMateriali(GL_FRONT,GL_SHININESS,128);

   makeList();
}


void PumpkinWij::paintGL()
{
   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

   // draw main scene
   draw();

   //iterate through drawing shapes

   glFlush();
}


//almost entirely copied from Dr. Merkley's og4.cpp
void PumpkinWij::resizeGL(int width, int height)
{
   GLfloat w = (float) width / (float) height;
   GLfloat h = 1.0;

   glViewport( 0, 0, width, height );
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   float near_clip = 4.0, far_clip = 250.0;
   glFrustum( -w, w, -h, h, near_clip, far_clip );
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   float fov = FOV(width, height, near_clip, far_clip);
   //Should replace 3. with max object size
   float eyeLook = 36./(2*tan(fov/2-1.)) + 3./2.0;
   glTranslatef( 0.0, 0.0, -eyeLook );
}


//almost entirely copied from Dr. Merkley's og4.cpp
float PumpkinWij::FOV (int width, int height, float near_clip, float far_clip)
{
   // Get rid of compiler warnings and figure out what
   // to do about change in width later!
   width = width;
   near_clip = near_clip;
   float halfHeight = height/2;
   float fov = 2 * atan(halfHeight/far_clip);

   return fov;
}


void PumpkinWij::makeList()
{
   GLUquadricObj *q = gluNewQuadric();

   // pumpkin
   pumpkinList = glGenLists(1);
   glNewList(pumpkinList, GL_COMPILE);

      glPushMatrix();

      // sphere/gourd
      glColor3f((247.0/255.0), (166.0/255.0), (55.0/255.0)); // make it orange
      gluSphere(q, 1.0, 8, 20);

      // stem
      glColor3f((129.0/255.0), (85.0/255.0), (41.0/255.0)); // make it brown

      glTranslated(0.0, 0.0, 0.9);
      gluCylinder(q, 0.2, 0.14, 0.33, 7, 7);

      glTranslated(0.0, 0.0, 0.33);
      gluDisk(q, 0, 0.14, 7, 2);

      glPopMatrix();

   glEndList();

   // floor
   groundList = glGenLists(1);
   glNewList(groundList, GL_COMPILE);

      glColor3f((21.0/255.0), (72.0/255.0), (13.0/255.0)); // make it green
      glBegin(GL_QUADS);
         glVertex3f(0.0, 0.5, 0.0);
         glVertex3f(0.0, -0.5, 0.0);
         glVertex3f(1.0, -0.5, 0.0);
         glVertex3f(1.0, 0.5, 0.0);
      glEnd();

   glEndList();

   // wall
   wallList = glGenLists(1);
   glNewList(wallList, GL_COMPILE);

      glColor3f(0.3, 0.3, 0.3); // make it gray
      glBegin(GL_QUADS);
         glVertex3f(0.0, 0.5, 0.0);
         glVertex3f(0.0, 0.5, 1.0);
         glVertex3f(0.0, -0.5, 1.0);
         glVertex3f(0.0, -0.5, 0.0);
      glEnd();

   glEndList();

   // fake shadow
   fakeList = glGenLists(1);
   glNewList(fakeList, GL_COMPILE);

      glColor3f((239.0/255.0), (247.0/255.0), (147.0/255.0)); // make it yellow
      glBegin(GL_QUADS);
         glVertex3f(0.0, 0.5, 0.0);
         glVertex3f(0.0, 0.0, 0.5);
         glVertex3f(0.0, -0.5, 0.0);
         glVertex3f(0.0, -0.5, -0.5);
      glEnd();

   glEndList();

   delete q;
}
