
#include <GL/glew.h>
#include <stdio.h>

// All headers are automatically included from "iglu.h"
#include "iglu.h"

// IGLU classes and constants are all inside the iglu namespace.
using namespace iglu;

// Anything with a ::Ptr is a pointer-like type.  
IGLUOBJReader::Ptr      objReader = 0;
IGLUShaderProgram::Ptr  shader = 0;
IGLUTrackball::Ptr		ball = 0;
IGLUBuffer::Ptr         colorBuffer = 0;
IGLUTextureBuffer::Ptr  texBuffer = 0;

// Some data that will be passed to our shader
IGLUMatrix4x4           proj  = IGLUMatrix4x4::Identity();
IGLUMatrix4x4           model = IGLUMatrix4x4::Identity();
int                     currentColor=0;

// Data that will be passed to our shader inside a texture buffer
float colors[]  = { 1.0, 1.0, 1.0, 1.0,  // White
	                1.0, 0.0, 0.0, 1.0,  // Red
                    0.0, 1.0, 0.0, 1.0,  // Green
					0.0, 0.0, 1.0, 1.0,  // Blue
					1.0, 0.0, 1.0, 1.0,  // Purple
					1.0, 1.0, 0.0, 1.0,  // Yellow
					0.0, 1.0, 1.0, 1.0,  // Cyan
					1.0, 0.5, 0.0, 1.0,  // Orange
					1.0, 0.5, 0.5, 1.0,  // Pink
					0.3, 0.3, 0.3, 1.0,  // Dark Grey
};

void display ( void )
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	shader->Enable(); 
	    shader["project"]   = proj;
		shader["modelview"] = model * ball->GetMatrix();
		shader["colorNum"]  = currentColor;
		objReader->Draw( shader ); 
	shader->Disable(); 

	glutSwapBuffers();
}


void keys(unsigned char key, int x, int y)
{
	if (key == 'q' || key == 'Q' || key == 27)  // Quit on a 'q' or Escape
		exit(0);
	else
		currentColor = (currentColor+1)%10;
}

void idle ( void )
{
	glutPostRedisplay();
}

void mouse( int button, int state, int x, int y )
{
	if ( state == GLUT_DOWN )
		ball->SetOnClick( x, y );
	else if (state == GLUT_UP )
		ball->Release();
}

void motion( int x, int y )
{
	ball->UpdateOnMotion( x, y ); 
	glutPostRedisplay();
}


void reshape( int w, int h )
{
	glViewport( 0, 0, w, h );
	ball->ResizeInteractorWindow( w, h );
	glutPostRedisplay();
}

int main(int argc, char** argv)
{
	// Standard OpenGL/GLUT setup
	glutInit(&argc, argv);
	glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
	glutInitWindowSize( 512, 512 );
	glutInitWindowPosition( 20, 20 );
	glutCreateWindow( "Basic GLSL Texture Buffer Sample" );
	glewInit();
	glutDisplayFunc( display );
	glutReshapeFunc( reshape );
	glutIdleFunc( idle );
	glutKeyboardFunc( keys );
	glutMouseFunc( mouse );
	glutMotionFunc( motion );

	// Load the texture with IGLU
	printf("(+) Loading object...\n" );
	objReader  = new IGLUOBJReader( "../../CommonSampleFiles/models/cow.obj" );

	// Create a virtual trackball
	ball = new IGLUTrackball( 512, 512 );

	// Setup the viewing matrices
	proj  = IGLUMatrix4x4::Perspective( 60, 1, 3, 20 );
	model = IGLUMatrix4x4::Translate( 0, 0, -11 );

	// Load a shader for the object
	printf("(+) Loading shaders...\n" );
	shader = new IGLUShaderProgram( "simpleTexBuffer.vert.glsl", "simpleTexBuffer.frag.glsl" );
	shader->SetProgramEnables( IGLU_GLSL_DEPTH_TEST ); 

	// Create a buffer to store out set of colors
	printf("(+) Creating a GPU buffer...\n");
	colorBuffer = new IGLUBuffer();
	colorBuffer->SetBufferData( sizeof( colors ), colors, IGLU_STATIC|IGLU_DRAW );

	// Create a texture buffer to pass our colors to GLSL in a 'samplerBuffer'
	printf("(+) Creating a texture buffer...\n");
	texBuffer = new IGLUTextureBuffer();
	texBuffer->BindBuffer( GL_RGBA32F, colorBuffer );

	// Set the shader's samplerBuffer to look at texBuffer.
	shader["colorTex"] = texBuffer;

	// Start the GLUT interaction loop
	glutMainLoop();
	return 0;
}
