/*****************************************************************
  drawOrder0.c
  by Dave Pape
  9 Feb 2003
  
  This program demonstrates the effect of drawing order on blended
  transparency.  It draws an opaque sphere, with a 50% transparent
  red cube in front of it.
  Hitting the spacebar toggles between two modes:
   In the default mode, the sphere is rendered first.
   In the alternate mode, the sphere is rendered second.  In this
   case, the cube will be seen to completely hide the sphere, and
   not be properly blended with it.
  
*****************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <GL/glut.h>
#include <GL/gl.h>

float viewRotY = 0, viewRotX = 0, cameraDistance = 10;
int drawSphereFirst = 1;

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[])
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(512, 512);
    glutCreateWindow(argv[0]);
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutSpecialFunc(specialkey);
    glutMainLoop();
    return 0;
    }


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

    glLoadIdentity();

    initLight();

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    glTranslatef(0.0, 0.0, -cameraDistance);
    glRotatef(viewRotX, 1.0, 0.0, 0.0);
    glRotatef(viewRotY, 0.0, 1.0, 0.0);

/*************** CODE OF INTEREST ******************************/
/*    If the flag 'drawSphereFirst' is true, we draw the       */
/*    opaque sphere before drawing the transparent cube.       */
/*                                                             */
    if (drawSphereFirst)                                     /**/
        {                                                    /**/
        glMaterialfv(GL_FRONT, GL_DIFFUSE, white);           /**/
        glPushMatrix();                                      /**/
         glTranslatef(0.0, 0.0, -5.0);                       /**/
         glutSolidSphere(2.5, 16, 8);                        /**/
        glPopMatrix();                                       /**/
        glMaterialfv(GL_FRONT, GL_DIFFUSE, red);             /**/
        glutSolidCube(2.0);                                  /**/
        }                                                    /**/
/*                                                             */
/*    Otherwise, we draw them in the reverse order             */
/*                                                             */
    else                                                     /**/
        {                                                    /**/
        glMaterialfv(GL_FRONT, GL_DIFFUSE, red);             /**/
        glutSolidCube(2.0);                                  /**/
        glMaterialfv(GL_FRONT, GL_DIFFUSE, white);           /**/
        glPushMatrix();                                      /**/
         glTranslatef(0.0, 0.0, -5.0);                       /**/
         glutSolidSphere(2.5, 16, 8);                        /**/
        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 == '-')
        cameraDistance += 1;
    else if (k == '=')
        cameraDistance -= 1;
    else if (k == ' ')
        drawSphereFirst = !drawSphereFirst;
    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();
    }

