#include <windows.h>	// for the windows file dialog
#include <string.h>		// string functions (strcpy)
#include <GL/glut.h>	// hmmm
#include "FreeImage.h"	// Our image library
#pragma comment (lib, "FreeImage.lib")	// link with the FreeImage.lib library

unsigned int	g_unTexID;	// The ID of our texture

// Modified open dialog to open any file
bool FileOpenDlg(char savedFilename[256])
{
	char szFileName[256] = "";
    OPENFILENAME ofn;
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = sizeof(szFileName);
    ofn.lpstrFilter = "JPG\0*.jpg\0PPM\0*.ppm\0BMP\0*.bmp\0All\0*.*\0\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_SHAREAWARE;
 
    if (GetOpenFileName(&ofn))
	{
		strcpy(savedFilename, szFileName);
		/* flip all '\' to '/' */
		for(char *p = savedFilename; *p != '\0'; p++)
			if(*p == '\\')
				*p = '/';

		return true;
	}
	return false;
}

void display()
{
	glClear(GL_COLOR_BUFFER_BIT);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, g_unTexID);
	glBegin(GL_QUADS);
	glTexCoord2f(0,0);	glVertex2f(-5, -5);
	glTexCoord2f(1,0);	glVertex2f( 5, -5);
	glTexCoord2f(1,1);	glVertex2f( 5, 5);
	glTexCoord2f(0,1);	glVertex2f(-5, 5);
	glEnd();
	glutSwapBuffers();
}

void reshape(int w, int h)
{
	glViewport(0,0, w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60, (float)w/h, 0.1, 100);

	glMatrixMode(GL_MODELVIEW);
	gluLookAt(0,0,10, 0,0,0,  0,1,0);
}


// The init function will load the texture
// The textures should be in square sizes in powers of 2
void init()
{
	char filename[256];
	if(!FileOpenDlg(filename))
		exit(0);

	FIBITMAP *image=0; // this will represent the image we will load

	// figure out which type of file we're dealing with	

	char *type = strrchr(filename, '.');
	if(strcmp(type, ".ppm")==0)
		image = FreeImage_Load(FIF_PPMRAW, filename);
	else if(strcmp(type, ".jpg")==0)	// for jpeg, uncompress accurately
		image = FreeImage_Load(FIF_JPEG, filename, JPEG_ACCURATE);
	else if(strcmp(type, ".bmp")==0)	// otherwise, just use default settings
		image = FreeImage_Load(FIF_BMP, filename);

	if(!image)
		exit(0);  // Image type not supported!  You should implement more if else statements

	// get the size of our image
	int w = FreeImage_GetPitch(image);
	int h = FreeImage_GetHeight(image);
	int bpp = FreeImage_GetBPP(image);
	bpp /= 8;	// convert from bits to bytes
	w /= bpp;	// convert width from bytes in row, to just number of pixels in row
    
	////////////////////////////////////////////////
	// convert our widths and heights to powers of 2
	// NOTE: This code is pretty unreadable, but it essentially
	// rounds w and h to some power of 2.
	// This might even be broken! 
	int i, wp=w, hp=h;
	for(i=0; wp != 0; wp /= 2) i++;
	if( (2 << (i-2)) != w)	// check if it already was a power of 2
		w = 2 << (i-1);		// otherwise, round up

	for(i=0; hp != 0; hp /= 2) i++;
	if( (2 << (i-2)) != h)	// check if it already was a power of 2
		h = 2 << (i-1);		// otherwise, round up


	//////////////////////////
	// Create our texture data
	//////////////////////////

	unsigned char *texData = new unsigned char[w*h*3];

	FreeImage_ConvertToRawBits(texData, image, w*3, 24, 0, 0, 0);
	
	///////////////////////////////////////////////////
	// texData now contains our image.  However we need to 
	// swap the red and blue color channels and flip the scanlines
	// in the vertical direction
	// This is because of the difference between how OpenGL and FreeImage
	// store image data internally.
	///////////////////////////////////////////////////
	
	int linesize = w*3;

	// flip color components
	for(int y=0; y < h; y++)
	{
		int pos = y*linesize;
        for(int x=0; x < w; x++)
		{
			int xpos = y*linesize + x*3;
			unsigned char temp = texData[xpos];
			texData[xpos] = texData[xpos+2];
			texData[xpos+2] = temp;
		}	
	}

	// flip scanlines from top half with bottom half
	unsigned char *line = new unsigned char[w*3];	

	// swap top and bottom scanlines
	for(y=0; y < h/2; y++)
	{
		int pos = y*linesize;
		int spos = (h-y-1)*linesize;	// position to switch with
		if(spos != pos)		
		{
			memcpy(line, &texData[pos], linesize);
			memcpy(&texData[pos], &texData[spos], linesize);
			memcpy(&texData[spos],line, linesize);
		}
	}
	delete [] line;
	
	// now put texture data in opengl
	glGenTextures(1, &g_unTexID);
	glBindTexture(GL_TEXTURE_2D, g_unTexID);

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 
		w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texData);

	// release files
	delete [] texData;
	FreeImage_Unload(image);

}

int main()
{
	
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutCreateWindow("Sample Texture loader");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
    init();
	glutMainLoop();
	return 0;
}