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

float viewRotY = 0, viewRotX = 0;
int ambient = 0;

void drawEverything(void);
void initLight(void);
void drawCoordinateAxes(void);
void checkGLError(char *);
void key(unsigned char k, int x, int y);
void specialkey(int k, int x, int y);



int main(int argc, char *argv[])
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("example");
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutSpecialFunc(specialkey);
    glutMainLoop();
    return 0;
    }


void drawEverything(void)
    {
    GLfloat red[4] = { 1, 0, 0, 1 };
    GLfloat green[4] = { 0, 1, 0, 1 };
    GLfloat blue[4] = { 0, 0, 1, 1 };
    GLfloat black[4] = { 0, 0, 0, 1 };
    GLfloat white[4] = { 1, 1, 1, 1 };
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50.0, 1.0, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    initLight();

    glTranslatef(0.0, 0.0, -35.0);
    glRotatef(viewRotX, 1.0, 0.0, 0.0);
    glRotatef(viewRotY, 0.0, 1.0, 0.0);
    
    glEnable(GL_LIGHTING);

    if (ambient)
        glMaterialfv(GL_FRONT, GL_AMBIENT, white);
    else
        glMaterialfv(GL_FRONT, GL_AMBIENT, black);
    
	glMaterialfv(GL_FRONT, GL_DIFFUSE, green);
    glBegin(GL_QUADS);
     glNormal3f(0.0, 0.0, 1.0);
     glVertex3f(-3.0, 1.0, -1.0);
     glVertex3f(3.0, 1.0, -1.0);
     glVertex3f(3.0, 7.0, -1.0);
     glVertex3f(-3.0, 7.0, -1.0);
    glEnd();

	glMaterialfv(GL_FRONT, GL_DIFFUSE, red);
    glBegin(GL_QUADS);
     glNormal3f(-0.707, 0.0, 0.707);
     glVertex3f(-9.0, 1.0, -7.0);
     glVertex3f(-3.0, 1.0, -1.0);
     glVertex3f(-3.0, 7.0, -1.0);
     glVertex3f(-9.0, 7.0, -7.0);
    glEnd();

	glMaterialfv(GL_FRONT, GL_DIFFUSE, blue);
    glBegin(GL_QUADS);
     glNormal3f(0.707, 0.0, 0.707);
     glVertex3f(3.0, 1.0, -1.0);
     glVertex3f(9.0, 1.0, -7.0);
     glVertex3f(9.0, 7.0, -7.0);
     glVertex3f(3.0, 7.0, -1.0);
    glEnd();

    glDisable(GL_LIGHTING);
    
    drawCoordinateAxes();
    
    glutSwapBuffers();
    
    checkGLError("end-of-frame");
    }


void initLight(void)
    {
    GLfloat white[4] = { 1, 1, 1, 1 };
    GLfloat black[4] = { 0, 0, 0, 1 };
    GLfloat grey[4] = { 0.1, 0.1, 0.1, 1 };
    GLfloat lightPos[4] = {-1, 1, 1, 0};
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
	glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    if (ambient)
        glLightfv(GL_LIGHT0, GL_AMBIENT, grey);
    else
        glLightfv(GL_LIGHT0, GL_AMBIENT, black);
    }


void drawCoordinateAxes(void)
    {
    glLineWidth(2.0);
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_LINES);
     glVertex3f(-1.0, 0.0, 0.0);
     glVertex3f(1.0, 0.0, 0.0);
     glVertex3f(0.0, -1.0, 0.0);
     glVertex3f(0.0, 1.0, 0.0);
     glVertex3f(0.0, 0.0, -1.0);
     glVertex3f(0.0, 0.0, 1.0);
    glEnd();
    glLineWidth(1.0);
    glColor3f(1.0, 0.0, 0.0);
    glRasterPos3f(1.0, 0.0, 0.0);
    glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'X');
    glRasterPos3f(0.0, 1.0, 0.0);
    glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'Y');
    glRasterPos3f(0.0, 0.0, 1.0);
    glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'Z');
    }


void checkGLError(char *prefix)
    {
    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
        printf("%s GL error '%s'\n",prefix,gluErrorString(err));
    }


void key(unsigned char k, int x, int y)
    {
    if (k == 27)
        exit(0);
    else if (k == 'a')
        ambient = !ambient;
    glutPostRedisplay();
    }


void specialkey(int k, int x, int y)
    {
    if (k == GLUT_KEY_LEFT)
        viewRotY += 3;
    else if (k == GLUT_KEY_RIGHT)
        viewRotY -= 3;
    else if (k == GLUT_KEY_UP)
        viewRotX += 3;
    else if (k == GLUT_KEY_DOWN)
        viewRotX -= 3;
    glutPostRedisplay();
    }
