/*  planets.c
 *  This program shows how to composite modeling transformations
 *  to draw translated and rotated models.
 *  Interaction:  pressing the d and y keys (day and year)
 *  alters the rotation of the planets around the sun.
 */
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>

static int year = 0;
static int day = 0;
static int winWidth = 600;
static int winHeight = 400;

void init(void) /* set up one light (diffuse) */
{
   GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0};
   GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
   GLfloat position[] = {0.0, 0.0, -3.0, 1.0};

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
   glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
   glLightfv(GL_LIGHT0, GL_POSITION, position);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_AUTO_NORMAL);

   glClearColor (0.0, 0.0, 0.0, 0.0); /* black background */
   glShadeModel (GL_SMOOTH);
}
static writeText(GLfloat x, GLfloat y, GLfloat z, GLfloat size, char * msg)
{
  char * p;
  GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0};

  glPushMatrix();
    glLoadIdentity ();
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); 
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glTranslatef(x, y, z);
    glScalef(size/1000.0, size/1000.0, 0.0);
    for(p=msg; *p; p++)
      glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  glPopMatrix();
}

void display(void) /* spheres of various colors for light */
{
   GLfloat red_ambient[]  = { 0.4, 0.0, 0.0, 1.0 }; /* red ambient */
   GLfloat red_diffuse[] =  { 0.6, 0.0, 0.0, 1.0 }; /* red diffuse */
   GLfloat blue_ambient[]  = { 0.0, 0.0, 0.4, 1.0 }; /* blue ambient */
   GLfloat blue_diffuse[] =  { 0.0, 0.0, 0.6, 1.0 }; /* blue diffuse */
   GLfloat moon_ambient[]  = { 0.4, 0.4, 0.4, 1.0 }; /* white ambient */
   GLfloat moon_diffuse[] =  { 0.6, 0.6, 0.6, 1.0 }; /* white diffuse */
   GLfloat sun_ambient[]  = { 1.0, 1.0, 0.0, 0.0 }; /* sun ambient */
   GLfloat sun_diffuse[] =  { 1.0, 1.0, 0.0, 0.0 }; /* sun diffuse */

   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glPushMatrix();
     glMaterialfv(GL_FRONT, GL_AMBIENT, sun_ambient);
     glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_diffuse);
     glMaterialfv(GL_BACK, GL_AMBIENT, sun_ambient);
     glMaterialfv(GL_BACK, GL_DIFFUSE, sun_diffuse);
     glutSolidSphere(1.0, 24, 24);   /* draw sun */
     glPushMatrix();
       glRotatef ((GLfloat)(year%360), 0.0, 1.0, 0.0);
       glTranslatef (2.0, 0.0, 0.0);
       glRotatef ((GLfloat)(day%360), 0.0, 1.0, 0.0);
       glMaterialfv(GL_FRONT, GL_AMBIENT, blue_ambient);
       glMaterialfv(GL_FRONT, GL_DIFFUSE, blue_diffuse);
       glutSolidSphere(0.3, 12, 12);    /* draw blue planet */
       glPushMatrix();
         glRotatef ((GLfloat)((12*year)%360), 0.0, 1.0, 0.0);
         glTranslatef (0.4, 0.0, 0.0);
         glRotatef ((GLfloat)((day/30)%360), 0.0, 1.0, 0.0);
         glMaterialfv(GL_FRONT, GL_AMBIENT, moon_ambient);
         glMaterialfv(GL_FRONT, GL_DIFFUSE, moon_diffuse);
         glutSolidSphere(0.07, 10, 10);    /* draw moon */
       glPopMatrix();
     glPopMatrix();
     glPushMatrix();
       glRotatef ((GLfloat)((year/2)%360), 0.0, 1.0, 0.0);
       glTranslatef (3.0, 0.0, 0.0);
       glRotatef ((GLfloat)((day/2)%360), 0.0, 1.0, 0.0);
       glMaterialfv(GL_FRONT, GL_AMBIENT, red_ambient);
       glMaterialfv(GL_FRONT, GL_DIFFUSE, red_diffuse);
       glutSolidSphere(0.2, 12, 12);    /* draw red planet */
     glPopMatrix();
   glPopMatrix();
   writeText(-1.5, -1.1, -2.0, 1.0, "press and hold  y  for year,  d  for day");
   glutSwapBuffers();
}

void reshape (int w, int h)
{
  winWidth = w;
  winHeight = h;
  glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
  /*            angle        aspect             near far */
  /*                                    -1.0 < Z < -20.0 */
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  /*     eye X    Y    Z  c X    Y    Z  up X    Y    Z */
  glEnable(GL_DEPTH_TEST);
}

void keyboard (unsigned char key, int x, int y)
{
  switch (key) {
    case 'd':
      day = day + 10;
      glutPostRedisplay();
      break;
    case 'D':
      day = day - 10;
      glutPostRedisplay();
      break;
    case 'y':
      year = year + 5;
      glutPostRedisplay();
      break;
    case 'Y':
      year = year - 5;
      glutPostRedisplay();
      break;
    case 27:
      exit(0);
      break;
    default:
      break;
   }
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (winWidth, winHeight); 
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display); 
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
}

