// Some of you might be wondering about animating your textures. Well I have
// some bad news for you. OpenGL does not support texture animation. So you
// will have no luck loading in a Gif or Movie file into your application and
// rendering it straight to your shape. But I also have some good news. There are
// ways around this. And I am going to show you the way that I know.

// Now my way consists of creating a different image file for every frame in your
// animation. If you have a gif file, you can probably find an exporter through a
// quick search on the internet to render out every frame from your animation.

// So why don't we get started.

// I am only adding one extra variable which will control which frame we are
// currently displaying for our animation. You will probably need another
// variable for each animation you wish you use. And this variable is simple
// enough to call. I am just using:
// double frame;

// Now we don't have to set our frame to 0 at the start of our application
// because if we do not set a value, it will default to 0.

// So far so good?

// After that I am then loading every frame when the application loads as a
// new part of the texture array. There are 9 files in total, so I am loading
// them as 0-8 in my array.
//	texture[0] = LoadTextureRAW( "textures/1.raw", 256, 256 );
//	texture[1] = LoadTextureRAW( "textures/2.raw", 256, 256 );
//	texture[2] = LoadTextureRAW( "textures/3.raw", 256, 256 );
//	texture[3] = LoadTextureRAW( "textures/4.raw", 256, 256 );
//	texture[4] = LoadTextureRAW( "textures/5.raw", 256, 256 );
//	texture[5] = LoadTextureRAW( "textures/6.raw", 256, 256 );
//	texture[6] = LoadTextureRAW( "textures/7.raw", 256, 256 );
//	texture[7] = LoadTextureRAW( "textures/8.raw", 256, 256 );
//	texture[8] = LoadTextureRAW( "textures/9.raw", 256, 256 );

// Now if we go to our display function, this is where we are going to set the
// texture to our quad. I am simply calling our Texture array as the texture, with
// the array number being which frame of the animation we are on. The (int) is to
// set our frame to an integer.
// glBindTexture( GL_TEXTURE_2D, texture[(int)frame] );

// Then I am going to add at the bottom of our display function, the code
// that will update which frame we are currently on for the current animation.

// So our function will look like:
// Here we are increasing which frame of the animation we are on each pass of the
// display function. Changing this number will change the speed of the animation.
//     frame+=0.2;
// Now I am checking to see if the frame is above the maximum, and if it is,
// change it back to the first frame for a steady loop.
//     if (frame > 8)
// 	   {
//     frame = 1;
//     }

// And if you run this you will have an animation of a man whose arms spin around.

// Well, have fun, but keep in mind that this can be time consuming. And I don't
// really see a use for it at this point in time.

// If you have any questions, email me at swiftless@gmail.com.

#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>

GLuint texture[8]; 

double frame;

GLuint LoadTexture( const char * filename, int width, int height )
{
	GLuint texture;
	unsigned char * data;
	FILE * file;

	//The following code will read in our RAW file
	file = fopen( filename, "rb" );
	if ( file == NULL ) return 0;
	data = (unsigned char *)malloc( width * height * 3 );
	fread( data, width * height * 3, 1, file );
	fclose( file );

	glGenTextures( 1, &texture ); //generate the texture with the loaded data
	glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it's array
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); //set texture environment parameters

	//here we are setting what textures to use and when. The MIN filter is which quality to show
	//when the texture is near the view, and the MAG filter is which quality to show when the texture
	//is far from the view.

	//The qualities are (in order from worst to best)
	//GL_NEAREST
	//GL_LINEAR
	//GL_LINEAR_MIPMAP_NEAREST
	//GL_LINEAR_MIPMAP_LINEAR

	//And if you go and use extensions, you can use Anisotropic filtering textures which are of an
	//even better quality, but this will do for now.
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );

	//Here we are setting the parameter to repeat the texture instead of clamping the texture
	//to the edge of our shape. 
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

	//Generate the texture with mipmaps
	gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data ); 
	free( data ); //free the texture
	return texture; //return whether it was successfull
}

void FreeTexture( GLuint texture )
{
  glDeleteTextures( 1, &texture ); 
}

void cube (void) {
	glBindTexture( GL_TEXTURE_2D, texture[(int)frame] );
	glScalef(2,2,1);
	glBegin (GL_QUADS);
	glTexCoord2d(0,0); 
	glVertex3f(-1,1,0);
    glTexCoord2d(1,0); 
	glVertex3f(1,1,0);
    glTexCoord2d(1,1); 
	glVertex3f(1,-1,0);
    glTexCoord2d(0,1); 
	glVertex3f(-1,-1,0);
	glEnd();
}

void display (void) {
	glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity(); 
	glEnable( GL_TEXTURE_2D );
	glTranslatef(0,0,-5);
	cube();
	glutSwapBuffers();
	frame+=0.2;
	if (frame > 8)
	{
	frame = 1;
	}
}
void reshape (int w, int h) {
	glViewport (0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
	glMatrixMode (GL_MODELVIEW);
}

void init (void) {
	texture[0] = LoadTexture( "textures/1.raw", 256, 256 );
	texture[1] = LoadTexture( "textures/2.raw", 256, 256 );
	texture[2] = LoadTexture( "textures/3.raw", 256, 256 );
	texture[3] = LoadTexture( "textures/4.raw", 256, 256 );
	texture[4] = LoadTexture( "textures/5.raw", 256, 256 );
	texture[5] = LoadTexture( "textures/6.raw", 256, 256 );
	texture[6] = LoadTexture( "textures/7.raw", 256, 256 );
	texture[7] = LoadTexture( "textures/8.raw", 256, 256 );
	texture[8] = LoadTexture( "textures/9.raw", 256, 256 );
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE);
	glutInitWindowSize (500, 500);
	glutInitWindowPosition (100, 100);
    glutCreateWindow ("A basic OpenGL Window");
	init();
    glutDisplayFunc (display);
	glutIdleFunc (display);
	glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}
