/* translate.c -- test translation  */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glut.h>

static int spin;

GLfloat xangle = 0.0;
int distancechange = 0;
int distance = 0;
int firstx = 0;
#define NUMBER_OF_STARS 100
float stars[NUMBER_OF_STARS][3];
float star_emissions[NUMBER_OF_STARS][3];

int first = 1;

void mouse_button (int button, int state, int x, int y)
{
  switch (button)
    {
      case GLUT_LEFT_BUTTON:
        //angle -= 1.0;
	if (state == GLUT_DOWN)
	    break;
	firstx = x;
	distance = 0;
	distancechange = 0;
	break;
      case GLUT_RIGHT_BUTTON:
        //angle += 1.0;
	if (state == GLUT_DOWN)
	    break;
	distance = 0;
	distancechange = 0;
	break;
      case GLUT_MIDDLE_BUTTON:
        exit (EXIT_SUCCESS);
	break;
    }
}

void mouse_move (int x, int y)
{
  distancechange = x - firstx - distance;
  distance = x - firstx;
}

void display ()
{
#if 1
  {
    GLfloat material_emission[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat material_diffuse[] = { 0.75, 0.75, 0.75, 1.0 };
    GLfloat material_specular[] = { 0.3, 0.3, 0.3, 1.0 };

    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
    glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 1000.0);
  }
#endif

  glClearColor (0.0, 0.0, 0.0, 0.0);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity ();

  xangle += 0.5 * distancechange;

  //glScalef (0.1, 0.1, 0.1);
  //glScalef (0.5, 0.5, 0.5);
  glRotatef (xangle, 0.0, 1.0, 0.0);

  glTranslatef (0.0, 0.0, -1.25);

#if 0
  glRotatef (20, 0.0, 1.0, 0.0);
  glRotatef (10, 0.0, 0.0, 1.0);
  glRotatef (5, 1.0, 0.0, 1.0);
#endif
  //glTranslatef (0.0, 0.0, -3.0);

  glColor3f (0.7, 0.7, 0.7);

  spin = (spin + 1) % 360;
#if 1
  glPushMatrix ();
  {
#if 0
    GLfloat pos[] = {0.0, 1.0, 0.0, 0.0};
    GLfloat dir[] = {0.0, -1.0, 0.0, 0.0};
    glRotatef (spin, 1.0, 0.0, 0.0);
#else
    GLfloat pos[] = {1.0, 1.0, 0.0, 0.0};
    GLfloat dir[] = {-1.0, -1.0, 0.0, 0.0};
    glRotatef (spin, 1.0, -1.0, 0.0);
#endif
    glLightfv (GL_LIGHT1, GL_POSITION, pos);
    glLightfv (GL_LIGHT1, GL_SPOT_DIRECTION, dir);
  }
  glPopMatrix ();
#endif

#if 1
  // Planets.

  //glutSolidCube (1);
  glColor3f (0.1, 0.7, 0.1);
  glPushMatrix ();
  {
    glRotatef (-10.0, 0.0, 0.0, 1.0);
    glRotatef (2 * spin, 0.0, 1.0, 0.0);
    glPushMatrix ();
    {
#define glutSphere glutSolidSphere
      glRotatef (90.0, 1.0, 0.0, 0.0);
      glutSphere (0.5, 80, 80);
      glTranslatef (0.7, 0.0, 0.0);
      glShadeModel (GL_SMOOTH);
      glutSphere (0.05, 10, 10);
      glShadeModel (GL_FLAT);
    }
    glPopMatrix ();
  }
  glPopMatrix ();
#endif

  // Stars.

#if 1
  {
    //GLfloat material_emission[] = { 0.0, 0.0, 0.0, 1.0 };
    //GLfloat material_emission[] = { 1.0, 1.0, 1.0, 1.0 };
    //GLfloat material_emission[] = { 0.8, 0.8, 0.8, 1.0 };
    GLfloat material_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_diffuse[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat material_specular[] = { 0.0, 0.0, 0.0, 1.0 };

    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material_ambient);
    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);
    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material_specular);
    //glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 0.0);
  }
#endif

#if 1
  glBegin (GL_POINTS);
  {
    int i;
    GLfloat material_emission[3];
    for (i = 0; i < NUMBER_OF_STARS; i++)
      {
	if (first) {
	    printf (": %f %f %f  %f %f %f\n", stars[i][0], stars[i][1], stars[i][2],
		    star_emissions[i][0], star_emissions[i][1], star_emissions[i][2]);
	  }
	//GLfloat material_emission[] = { 0.4, 0.4, 0.4, 1.0 };
	material_emission[0] = 0.5; //star_emissions[i][0];
	material_emission[1] = 0.5; //star_emissions[i][0];
	material_emission[2] = 0.5; //star_emissions[i][0];
	//glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, *(star_emissions + i));
	glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material_emission);
	glVertex3f (stars[i][0], stars[i][1], stars[i][2]);
      }
    first = 0;
  }
  glEnd ();
#endif

  glFlush ();
  glutSwapBuffers ();
}

void reshape (GLsizei w, GLsizei h)
{
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  //glFrustum (-3.0, 3.0, -3.0, 3.0, 1.0, 3.0);
  //glFrustum (-3.0, 3.0, -3.0, 3.0, 0.5, 3.0);
  glFrustum (-1.0, 1.0, -1.0, 1.0, 0.5, 100.0);
  //glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
  //glFrustum (-1.0, 1.0, -1.0, 1.0, 0.0, 20.0);
  //glOrtho (-3.0, 3.0, -3.0, 3.0, 0.0, 500.0);

  glMatrixMode (GL_MODELVIEW);
  glViewport (0, 0, w, h);
}

int
main (int argc, char * argv[])
{
  GLfloat ones[] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat colour[] = { 1.0, 0.0, 1.0, 1.0 };

  puts (__FILE__);

  srand48 (1);

  spin = 0;

  glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  glutInitWindowPosition (100, 100);
  glutInitWindowSize (350, 350);

  glutInit (&argc, argv);

  glutCreateWindow (argv[0]);

  //glShadeModel (GL_SMOOTH);
  glShadeModel (GL_FLAT);

  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, ones);
  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 100.0);
  glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.1);
  glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.1);
  glLightfv (GL_LIGHT1, GL_DIFFUSE, colour);
  glLightfv (GL_LIGHT1, GL_SPECULAR, ones);

  {
#if 1
    //GLfloat pos[] = {-1.0, 0.0, 0.0, 0.0};
    //GLfloat dir[] = {1.0, 0.0, 0.0, 0.0};
    GLfloat pos[] = {0.0, 1.0, 0.0, 0.0};
    GLfloat dir[] = {0.0, -1.0, 0.0, 0.0};
    glLightfv (GL_LIGHT0, GL_POSITION, pos);
    glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, dir);
#endif
    glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180);
    glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 10);

    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glEnable (GL_LIGHT1);
    //glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
    glLightModelf (GL_LIGHT_MODEL_LOCAL_VIEWER, 1);

    glDepthFunc (GL_LEQUAL);
    glEnable (GL_DEPTH_TEST);
  }

  // Generate star positions and emissions.

  {
    int i;
    for (i = 0; i < NUMBER_OF_STARS; i++)
      {
	stars[i][0] = 3 - drand48 () * 6;
	stars[i][1] = 3 - drand48 () * 6;
	stars[i][2] = 3 - drand48 () * 6;
	//star_emissions[i][0] = star_emissions[i][1] = star_emissions[i][2] = rand () % 10;
	star_emissions[i][0] = drand48 () * 10;
	star_emissions[i][1] = star_emissions[i][0];
	star_emissions[i][2] = star_emissions[i][1];
	printf ("%f %f %f  %f %f %f\n", stars[i][0], stars[i][1], stars[i][2],
		star_emissions[i][0], star_emissions[i][1], star_emissions[i][2]);
      }
  }

  glutReshapeFunc (reshape);
  glutDisplayFunc (display);
  glutIdleFunc (display);
  glutMouseFunc (mouse_button);
  glutMotionFunc (mouse_move);

  glutMainLoop ();

  return EXIT_SUCCESS;
}
