//////////////////////////////////////////////////////////////////////////////
//
//  RenderFuncs.h
//
//////////////////////////////////////////////////////////////////////////////

#ifndef _RENDERFUNCS_H_
#define _RENDERFUNCS_H_

#include "Params.h"

enum Method {
  Technique1 = 0,
  Technique2,
  Technique3,
  Technique4,
  Technique5,
  NumMethods
};

char*  methodName[NumMethods] = {
  "Technique1",
  "Technique2",
  "Technique3",
  "Technique4",
  "Technique5",
};

struct ClearColor {
  GLfloat  r, g, b, a;
} clear[NumMethods] = {
  { 0, 0, 0, 1 },
  { 1, 0, 0, 1 },
  { 0, 1, 0, 1 },
  { 0, 0, 1, 1 },
  { 1, 0, 1, 1 },
};


//----------------------------------------------------------------------------
//
//  Rendering routines
//
//----------------------------------------------------------------------------
//
//  Technique 1: Render each cube and quad separately, with each quad bracked
//               within its own glBegin() / glEnd() pair.
//

void
render_1( void )
{
  int  i, j;
  GLfloat*  c = colorData;
  GLfloat (*v)[3] = (GLfloat (*)[3]) vertexData;

  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c );  c += 3;

    for ( j = 0; j < NUM_CUBE_FACES; ++j ) {
      glBegin( GL_QUADS );
      glVertex3fv( v[cubeFace[j][0]] );
      glVertex3fv( v[cubeFace[j][1]] );
      glVertex3fv( v[cubeFace[j][2]] );
      glVertex3fv( v[cubeFace[j][3]] );
      glEnd();
    } 
    v += NUM_CUBE_VERTICES;
  }
}

//----------------------------------------------------------------------------
//
//  Technique 2: Render each cube separately, with all of its quads
//               rendered within one glBegin() / glEnd pair.
//

void
render_2( void )
{
  int  i, j;
  GLfloat*  c = colorData;
  GLfloat (*v)[3] = (GLfloat (*)[3]) vertexData;

  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c );  c += 3;

    glBegin( GL_QUADS );
    for ( j = 0; j < NUM_CUBE_FACES; ++j ) {
      glVertex3fv( v[cubeFace[j][0]] );
      glVertex3fv( v[cubeFace[j][1]] );
      glVertex3fv( v[cubeFace[j][2]] );
      glVertex3fv( v[cubeFace[j][3]] );
    } 
    glEnd();
    v += NUM_CUBE_VERTICES;
  }
}

//----------------------------------------------------------------------------
//
//  Technique 3: Render each cube separately, with a single glBegin() /
//               glEnd() pair surrounding all of the cube rendering calls
//

void
render_3( void )
{
  int  i, j;
  GLfloat*  c = colorData;
  GLfloat (*v)[3] = (GLfloat (*)[3]) vertexData;

  glBegin( GL_QUADS );
  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c );  c += 3;
    for ( j = 0; j < NUM_CUBE_FACES; ++j ) {
      glVertex3fv( v[cubeFace[j][0]] );
      glVertex3fv( v[cubeFace[j][1]] );
      glVertex3fv( v[cubeFace[j][2]] );
      glVertex3fv( v[cubeFace[j][3]] );
    } 
    v += NUM_CUBE_VERTICES;
  }
  glEnd();
}

//----------------------------------------------------------------------------
//
//  Technique 4: Render each cube separately, rendering the top and bottom
//               faces as two independent quads, and the other four faces
//               as a quad strip
//

void
render_4( void )
{
  int  i, j;
  GLfloat*  c = colorData;
  GLfloat (*v)[3] = (GLfloat (*)[3]) vertexData;

  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c );  c += 3;

    glBegin( GL_QUADS );
    glVertex3fv( v[cubeFace[0][0]] );
    glVertex3fv( v[cubeFace[0][1]] );
    glVertex3fv( v[cubeFace[0][2]] );
    glVertex3fv( v[cubeFace[0][3]] );

    glVertex3fv( v[cubeFace[1][0]] );
    glVertex3fv( v[cubeFace[1][1]] );
    glVertex3fv( v[cubeFace[1][2]] );
    glVertex3fv( v[cubeFace[1][3]] );
    glEnd();

    glBegin( GL_QUAD_STRIP );
    for ( j = 2; j < NUM_CUBE_FACES; ++j ) {
      glVertex3fv( v[cubeFace[j][0]] );
      glVertex3fv( v[cubeFace[j][1]] );
    } 
    glVertex3fv( v[cubeFace[2][0]] );
    glVertex3fv( v[cubeFace[2][1]] );
    glEnd();

    v += NUM_CUBE_VERTICES;
  }
}

//----------------------------------------------------------------------------
//
//  Technique 5: Render the top and bottom faces of each cube in one pass
//               and render the remaining faces of each cubes as a quad
//               strip.
//

void
render_5( void )
{
  int  i, j;
  GLfloat*  c = colorData;
  GLfloat (*v)[3] = (GLfloat (*)[3]) vertexData;

  glBegin( GL_QUADS );
  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c );  c += 3;

    glVertex3fv( v[cubeFace[0][0]] );
    glVertex3fv( v[cubeFace[0][1]] );
    glVertex3fv( v[cubeFace[0][2]] );
    glVertex3fv( v[cubeFace[0][3]] );
		 
    glVertex3fv( v[cubeFace[1][0]] );
    glVertex3fv( v[cubeFace[1][1]] );
    glVertex3fv( v[cubeFace[1][2]] );
    glVertex3fv( v[cubeFace[1][3]] );

    v += NUM_CUBE_VERTICES;
  }
  glEnd();

  c = colorData;
  v = (GLfloat (*)[3]) vertexData;
  
  for ( i = 0; i < numPrimitives; ++i ) {
    glColor3fv( c ); c += 3;

    glBegin( GL_QUAD_STRIP );
    for ( j = 2; j < NUM_CUBE_FACES; ++j ) {
      glVertex3fv( v[cubeFace[j][0]] );
      glVertex3fv( v[cubeFace[j][1]] );
    } 
    glVertex3fv( v[cubeFace[2][0]] );
    glVertex3fv( v[cubeFace[2][1]] );
    glEnd();
    
    v += NUM_CUBE_VERTICES;
  }
}

//----------------------------------------------------------------------------
//
//  Function arrays
//


void (*render[])( void ) = {
  render_1,
  render_2,
  render_3,
  render_4,
  render_5
};

#endif /* ! _RENDERFUNCS_H_ */
