// Demonstration of blending: displays a blue icosahedron inside
// a transparent cube illuminated by a moving light source.

#include <iostream.h>
#include <iomanip.h>
#include <math.h>
#include <gl/glut.h>

GLfloat theta = 0.0;							// For light position
GLfloat phi = 0.0;								// For pyramid position
GLfloat glass[] = { 0.4f, 0.4f, 0.4f, 0.6f };	// Transparent material

// Constant colours and material factors.
const GLfloat blue[] = { 0.2f, 0.2f, 1.0f, 0.8f };
const GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
const GLfloat polished[] = { 100.0 };

// Light at origin.
const GLfloat light_pos[] = { 0.0, 0.0, 0.0, 1.0 };

void display () {
	// Display callback function.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0, 0.0, -10.0);

	// Use variable theta to position the light.
	glPushMatrix();
		glTranslatef(8.0 * sin(theta), 1.0, 8.0 * cos(theta));
		glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
	glPopMatrix();

	// Display a rotating blue shape ...
	glPushMatrix();
		glTranslatef(1.0, 0.0, 0.0);
		glRotatef(45.0, 1.0, 0.0, 0.0);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
		glMaterialfv(GL_FRONT, GL_SPECULAR, white);
		glMaterialfv(GL_FRONT, GL_SHININESS, polished);
		glTranslatef(-1.0, 0.0, 0.0);
		glRotatef(phi, 1.0, 0.5, 0.5);
		glutSolidIcosahedron();
	glPopMatrix();

	// ... inside a glass box
	glPushMatrix();
		glRotatef(30.0, 0.0, 1.0, 0.0);
		glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, glass);
		glMaterialfv(GL_FRONT, GL_SPECULAR, white);
		glMaterialfv(GL_FRONT, GL_SHININESS, polished);
		glutSolidCube(3.0);
	glPopMatrix();
	glutSwapBuffers();
}

void set_blend (int digit) {
	// Set blending factor ("alpha" component of "glass").
	double blend = digit / 10.0;
	cout << "Blending = " << setprecision(1) << blend << endl;
	glass[3] = blend;
}

void keyboard (unsigned char key, int x, int y) {
	// Use digit keys to set blending.
	if (key == 27)
		exit(0);
	else if ('0' <= key && key <= '9') 
		set_blend(key - '0');
}

void spin () {
	// Move the light and rotate the pyramid.
	theta += 0.01f;
	phi += 1.0;
	glutPostRedisplay();
}

void resize (int w, int h) {
	// Allow user to resize window.
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(40.0, GLfloat(w)/GLfloat(h), 1.0, 50.0);
}

void main (int argc, char *argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowPosition(400, 300);
	glutInitWindowSize(400, 400);
	glutCreateWindow("The Magic Sapphire");
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
	glLightfv(GL_LIGHT0, GL_SPECULAR, white);
	cout << 
		"The program displays a blue sapphire in a glass cube" << endl <<
		"while a light source rotates around the cube." << endl <<
		"Press 0, 1, 2, ..., 9 keys to change transparency of the cube." << endl <<
		"Press ESC to exit." << endl << endl;
	set_blend(4);
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutIdleFunc(spin);
	glutReshapeFunc(resize);
	glutMainLoop();
}


