/*
   Program to display a cube that moves around in space.

   Sample for description of events in OpenGL
   
   (c) 1999, Steve Cunningham
*/

#include "glut.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXHITS	200 // size of array to hold hit records for selection

GLint cubeColor1 =  1;
GLint cubeColor2 =  2;
GLint windW = 500, windH = 500, hit = -1;
GLint vp[4];
GLuint selectBuf[MAXHITS];

// set up overall light data, including specular=ambient=light colors
GLfloat light_position[]={ 10.0, 10.0, -10.0, 1.0 };
GLfloat light_color[]={ 1.0, 1.0, 1.0, 1.0 };
GLfloat ambient_color[]={ 0.2, 0.2, 0.2, 1.0 };
GLfloat mat_specular[]={ 1.0, 1.0, 1.0, 1.0 };

// prototypes for functions
GLint DoSelect(GLint x, GLint y);
void myinit(void);
void Mouse(int button, int state, int mouseX, int mouseY);
void cube(int i);
void render( GLenum mode );
void display( void );
void reshape(int w,int h);

void myinit(void)
{
        glClearColor( 0.0, 0.0, 1.0, 0.0 );
        glShadeModel(GL_SMOOTH);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular );
        glLightfv(GL_LIGHT0, GL_POSITION, light_position );
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color );
        glLightfv(GL_LIGHT0, GL_SPECULAR, light_color );
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color );

// standard attributes
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glEnable(GL_DEPTH_TEST);
}

// mouse callback
void Mouse(int button, int state, int mouseX, int mouseY)
{
	if (state == GLUT_DOWN) { /* find which object was selected */
		hit = DoSelect((GLint) mouseX, (GLint) mouseY);
	}
	glutPostRedisplay();
}

void cube(int i)
{
/* define a point data type */

    typedef GLfloat point3[3];

    point3 vertices[8]={{-1.0, -1.0, -1.0},
                        {-1.0, -1.0,  1.0},
                        {-1.0,  1.0, -1.0},
                        {-1.0,  1.0,  1.0},
                        { 1.0, -1.0, -1.0},
                        { 1.0, -1.0,  1.0},
                        { 1.0,  1.0, -1.0},
                        { 1.0,  1.0,  1.0} };

    point3 normals[6]={{ 0.0, 0.0, 1.0},
                       {-1.0, 0.0, 0.0},
                       { 0.0, 0.0,-1.0},
                       { 1.0, 0.0, 0.0},
                       { 0.0,-1.0, 0.0},
                       { 0.0, 1.0, 0.0} };

    GLfloat color1[]={1.0, 0.0, 0.0,1.0}, color2[]={0.0,1.0,0.0,1.0};
    GLfloat mat_shininess[]={ 50.0 };

//  draw our cube
	if (i==1){
    	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color1 );
    	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color1 );
    }
    if (i==2){
    	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color2 );
    	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color2 );
    }
    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess );
    glBegin(GL_QUADS);
      glNormal3fv(normals[0]);   // first quad: positive Z face
      glVertex3fv(vertices[1]);
      glNormal3fv(normals[0]);
      glVertex3fv(vertices[5]);
      glNormal3fv(normals[0]);
      glVertex3fv(vertices[7]);
      glNormal3fv(normals[0]);
      glVertex3fv(vertices[3]);
      glNormal3fv(normals[5]);   // second quad: positive Y face
      glVertex3fv(vertices[7]);
      glNormal3fv(normals[5]);
      glVertex3fv(vertices[6]);
      glNormal3fv(normals[5]);
      glVertex3fv(vertices[2]);
      glNormal3fv(normals[5]);
      glVertex3fv(vertices[3]);
      glNormal3fv(normals[2]);   // third quad: negative Z face
      glVertex3fv(vertices[2]);
      glNormal3fv(normals[2]);
      glVertex3fv(vertices[6]);
      glNormal3fv(normals[2]);
      glVertex3fv(vertices[4]);
      glNormal3fv(normals[2]);
      glVertex3fv(vertices[0]);
      glNormal3fv(normals[3]);  // fourth quad: positive X face
      glVertex3fv(vertices[5]);
      glNormal3fv(normals[3]);
      glVertex3fv(vertices[4]);
      glNormal3fv(normals[3]);
      glVertex3fv(vertices[6]);
      glNormal3fv(normals[3]);
      glVertex3fv(vertices[7]);
      glNormal3fv(normals[4]);  // fifth quad: negative Y face
      glVertex3fv(vertices[4]);
      glNormal3fv(normals[4]);
      glVertex3fv(vertices[5]);
      glNormal3fv(normals[4]);
      glVertex3fv(vertices[1]);
      glNormal3fv(normals[4]);
      glVertex3fv(vertices[0]);
      glNormal3fv(normals[1]);  // sixth quad: negative X face
      glVertex3fv(vertices[0]);
      glNormal3fv(normals[1]);
      glVertex3fv(vertices[1]);
      glNormal3fv(normals[1]);
      glVertex3fv(vertices[3]);
      glNormal3fv(normals[1]);
      glVertex3fv(vertices[2]);
    glEnd();
 }

GLint DoSelect(GLint x, GLint y)
{
  GLint hits, temp;

  glSelectBuffer(MAXHITS, selectBuf);
  glRenderMode(GL_SELECT);
  glInitNames();
  glPushName(0);

// set up the viewing model
  glPushMatrix();
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPickMatrix(x, windH - y, 4, 4, vp);
  glClearColor(0.0, 0.0, 1.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT);
  gluPerspective(60.0,1.0,1.0,30.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
//             eye point        center of view      up   */
  gluLookAt(10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

  render(GL_SELECT);  /* draw the scene for selection */

  glPopMatrix();
// find the number of hits recorded and reset mode of render
  hits = glRenderMode(GL_RENDER);
// reset viewing model
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0,1.0,1.0,30.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
//             eye point        center of view      up   */
  gluLookAt(10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// return the label of the object selected, if any
  if (hits <= 0) {
    return -1;
  }
  temp = cubeColor1; cubeColor1 = cubeColor2; cubeColor2 = temp;
  return selectBuf[3];
}
		
void render( GLenum mode )
{
// Always draw the two cubes, even if we are in GL_SELECT mode,
// because an object is selectable iff it is identified in the name
// list and is drawn in GL_SELECT mode
    if (mode == GL_SELECT)
       glLoadName(0);
    glPushMatrix();
    glTranslatef(  1.0,  1.0, -2.0 );
//	if (mode == GL_RENDER)
		cube(cubeColor2);
	glPopMatrix();
    if (mode == GL_SELECT)
       glLoadName(1);
	glPushMatrix();
    glTranslatef( -1.0, -2.0,  1.0 );
//	if (mode == GL_RENDER)
		cube(cubeColor1);
	glPopMatrix();
	glFlush();
	glutSwapBuffers();
}
		
void display( void )
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	render(GL_RENDER);
	glutSwapBuffers();
}

void reshape(int w,int h)
{
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glGetIntegerv(GL_VIEWPORT, vp); // get viewport data; needed by gluPickMatrix
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0,1.0,1.0,30.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	//           eye point        center of view      up
	gluLookAt(10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

void main(int argc, char** argv)
{

// Standard GLUT initialization
        glutInit(&argc,argv);
//      initialize for double buffering, RGB color, and depth tests
        glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
        glutInitWindowSize(windW,windH);
        glutInitWindowPosition(70,70);
        glutCreateWindow("choosing cubes");
        glutDisplayFunc(display);
        glutReshapeFunc(reshape);
        glutMouseFunc(Mouse);
        
        myinit();
        glutMainLoop();
}

