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

float viewRotY = 0, viewRotX = 0;

GLUquadricObj * quadric;


void drawEverything(void);
void initLight(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[])
    {
    printf("Controls:\n"
            "        p - draw with points\n"
            "        l - draw with lines\n"
            "        s - draw with silhoettes\n"
            "        f - draw with filled polygons\n");
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("example");
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutSpecialFunc(specialkey);
    quadric = gluNewQuadric();
    gluQuadricDrawStyle(quadric, GLU_FILL);
    glPointSize(2.0);
    glutMainLoop();
    return 0;
    }


void drawEverything(void)
    {
    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);
    
    glColor3f(0.0, 1.0, 1.0);
    glPushMatrix();
     glTranslatef(-12.0, 0.0, 0.0);
     gluSphere(quadric, 2.5, 32, 24);
    glPopMatrix();    
    
    glColor3f(1.0, 0.0, 1.0);
    glPushMatrix();
     glTranslatef(-4.0, 0.0, 0.0);
     gluCylinder(quadric, 2.5, 3.5, 4.0, 32, 4);
    glPopMatrix();    
    
    glColor3f(1.0, 1.0, 0.0);
    glPushMatrix();
     glTranslatef(4.0, 0.0, 0.0);
     gluDisk(quadric, 1.0, 3.5, 32, 4);
    glPopMatrix();    
    
    glColor3f(1.0, 1.0, 1.0);
    glPushMatrix();
     glTranslatef(12.0, 0.0, 0.0);
     gluPartialDisk(quadric, 1.0, 3.5, 32, 4, 15.0, 240.0);
    glPopMatrix();    
    
    
    glutSwapBuffers();

    checkGLError("end-of-frame");
    }


void initLight(void)
    {
    GLfloat white[4] = { 1, 1, 1, 1 };
    GLfloat lightPos[4] = {-1, 1, 1, 0};
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    }


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 == 'p')
        gluQuadricDrawStyle(quadric, GLU_POINT);
    else if (k == 'l')
        gluQuadricDrawStyle(quadric, GLU_LINE);
    else if (k == 's')
        gluQuadricDrawStyle(quadric, GLU_SILHOUETTE);
    else if (k == 'f')
        gluQuadricDrawStyle(quadric, GLU_FILL);
    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();
    }
