// Well due to a request, here is a tiling example for you all.

// -----------------------------------------------------------------

// To tile in OpenGL, it is not that easy to merge or combine textures to create a simple 2D tiling game.
// It is easier for us to draw a bunch of quads that take up the space of the world in which we want
// to tile and assign different textures to those quads according to what is in our map file.

// Here is the example map file that I am using for this tutorial:

// int cMap[10][10] = {
// 	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
// 	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
// 	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
// 	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
// };

// -------------------------------------------------------------------

// Now if you don't like storing this in your program, you can just as easily store all of this in a file and load
// it in when you need it.

// So now that we have our 'map', we want to load in our two textures for our two states, 1 or 0, which will be
// either grass or dirt in the case of the textures I have created.

// 1 will be dirt, and 0 will be grass.

// So as this is building on from the texturing tutorial, we need to create another variable to hold our
// other texture.
// GLuint texture2; //the array for our second texture

// Now that we have our textures, we need to load them in, do this just like you did in the texturing tutorial:

// Load our texture
// texture = LoadTexture("texture.raw", 256, 256);
// texture2 = LoadTexture("texture2.raw", 256, 256);

// glutMainLoop ();

// Free our texture
// FreeTexture(texture);
// FreeTexture(texture2);

// --------------------------------------------------------------------

// And now for the drawTiles() function. This function will be called in the display function and takes no parameters.

// void drawTiles (void) { //our function to draw the tiles
// First thing we want to do is start looping through the height of the map, the value of 10 here is specific
// to this application. If you have a bigger or smaller map, change this value as you need.
// 	for (int i = 0; i < 10; i++) //loop through the height of the map
// 	{
// Then we will want to loop through the width of the map, just as I said above, the value 10 is specific
// to this tutorial.
// 		for (int j = 0; j < 10; j++) //loop through the width of the map
// 		{
// Now here is where the main part of our tiling takes place, we need to check if the map value at the 
// current [i][j] position is either a 0 or a 1. If it is a 0, then we bind the grass texture to the quad
// that we are about to draw.
// 			if (cMap[i][j] == 0) //if the map at this position contains a 0
// 			{
// 				glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
// 			}
// Else we automatically assign it to dirt. If you have more than two states, you will need to make several if statements,
// and if you do not want a default, then you will remove the else and replace it with an if.
// 			else //otherwise
// 			{
// 				glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
// 			}
// 			
// The rest of the code draws a quad at the current i, j position we are at.
// Drawing a quad should be simple for you at this stage. So I will not explain it.
// 			glPushMatrix(); //push the matrix so that our translations only affect this tile
// 				glTranslatef(j, -i, 0); //translate the tile to where it should belong
// 
// 				glBegin (GL_QUADS); //begin drawing our quads
// 					glTexCoord2d(0.0, 0.0);
// 					glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord
// 
// 					glTexCoord2d(1.0, 0.0);
// 					glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to
// 
// 					glTexCoord2d(1.0, 1.0);
// 					glVertex3f(1.0, 1.0, 0.0);
// 
// 					glTexCoord2d(0.0, 1.0);
// 					glVertex3f(0.0, 1.0, 0.0);
// 				glEnd();
// 			glPopMatrix(); //pop the matrix
// 		} //end first loop
// 	} //end second loop
// }

// --------------------------------------------------------------------

// And there we have it, you can now create a 2D tiled map for use with a game. Simple wasn't it? :-)
// 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; //the array for our texture
GLuint texture2; //the array for our second texture

int cMap[10][10] = { //our map
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 1, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
	{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};


//function to load the RAW file

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 );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_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
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, 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 drawTiles (void) { //our function to draw the tiles
	for (int i = 0; i < 10; i++) //loop through the height of the map
	{
		for (int j = 0; j < 10; j++) //loop through the width of the map
		{
			if (cMap[i][j] == 0) //if the map at this position contains a 0
			{
				glBindTexture( GL_TEXTURE_2D, texture ); //bind our grass texture to our shape
			}
			else //otherwise
			{
				glBindTexture( GL_TEXTURE_2D, texture2 ); //bind our dirt texture to our shape
			}
			
			glPushMatrix(); //push the matrix so that our translations only affect this tile
				glTranslatef(j, -i, 0); //translate the tile to where it should belong

				glBegin (GL_QUADS); //begin drawing our quads
					glTexCoord2d(0.0, 0.0);
					glVertex3f(0.0, 0.0, 0.0); //with our vertices we have to assign a texcoord

					glTexCoord2d(1.0, 0.0);
					glVertex3f(1.0, 0.0, 0.0); //so that our texture has some points to draw to

					glTexCoord2d(1.0, 1.0);
					glVertex3f(1.0, 1.0, 0.0);

					glTexCoord2d(0.0, 1.0);
					glVertex3f(0.0, 1.0, 0.0);
				glEnd();
			glPopMatrix(); //pop the matrix
		} //end first loop
	} //end second loop
}

void display (void) {
	glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glLoadIdentity(); 
	glEnable( GL_TEXTURE_2D );
	glTranslatef(-5, 4, -20); //translate back a bit to view the map correctly
	drawTiles(); //draw our tiles
	glutSwapBuffers();
}
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);
}

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

	//Load our texture
	texture = LoadTexture("texture.raw", 256, 256);
	texture2 = LoadTexture("texture2.raw", 256, 256);

    glutMainLoop ();

	//Free our texture
	FreeTexture(texture);
	FreeTexture(texture2);

    return 0;
}
