#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib,"freeglut.lib")
#include <windows.h>
#include <stdio.h>
#include "GL\gl.h"		// GL Header File
#include "GL\glu.h"		// GL Utility Library(GLU)Header File
#include "GL\glut.h"	// GL Utility Toolkit(GlUT)Header File

//compiler g++
//buid options: -lglut -lGL -lGLU

//размеры окна
const int width = 640;
const int height = 480;

//двумерные текстурные координаты
float textures[6][4][2] =
{
	//текстурные координаты 1-й грани 
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
	//текстурные координаты 2-й грани 
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
	//текстурные координаты 3-й грани
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
	//текстурные координаты 4-й грани
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
	//текстурные координаты 5-й грани
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
	//текстурные координаты 6-й грани
	0.0, 0.0,
	1.0, 0.0,
	1.0, 1.0,
	0.0, 1.0,
};

//координаты граней куба(квадратов)
float cube[6][4][3] =
{
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,

-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,

-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,

-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,

-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,

1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
};

float xrot;
float yrot;
float zrot;
float ratio;

int rotation = 1;

//рисуем куб по координатам
void drawCube()
{
	int i, j;
	glDisable(GL_COLOR);
	glEnable(GL_TEXTURE_2D);
	for (i = 0; i < 6; i++)
	{
		glBindTexture(GL_TEXTURE_2D, i + 1);
		//если текстуры разные  
		//glBindTexture(GL_TEXTURE_2D, i);  
		glBegin(GL_QUADS);
		for (j = 0; j < 4; j++)
		{
			glTexCoord2f(textures[i][j][0], textures[i][j][1]);
			glVertex3f(cube[i][j][0], cube[i][j][1], cube[i][j][2]);
		}
		glEnd();
	}
	glDisable(GL_TEXTURE_2D);
	glEnable(GL_COLOR);
}

GLuint LoadTexture(GLuint tex, const char* filename, int width, int height)
{
	//стандартный bmp 24 бит
	unsigned char* data;
	unsigned char R, G, B;
	FILE* file;

	//загрузка изображения из .bmp файла
	file = fopen(filename, "rb");

	if (file == NULL)return 0;
	//выделяем память под переменную data
	data = (unsigned char*)malloc(width * height * 3);
	//смещение для пропуска служебных данных
	BITMAPFILEHEADER header, * p;
	p = &header;
	fseek(file, 0, 0);
	fread(p, sizeof(header), 1, file);
	//смещение для пропуска служебных данных
	fseek(file, header.bfOffBits, 0);

	//читаем весь файл file в одну переменную data
	fread(data, width * height * 3, 1, file);
	//закрываем файл
	fclose(file);


	//переставляем местами R,G,B значения для правильного отображения цвета
	int index;
	for (int i = 0; i < width * height; ++i)
	{
		index = i * 3;
		B = data[index]; G = data[index + 1]; R = data[index + 2];
		data[index] = R; data[index + 1] = G; data[index + 2] = B;
	}

	//создаем текстуру из загруженного изображения
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);

	// фильтрация текстуры

	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

	//текстура создана и поэтому теперь можно
	//освобождить память от загруженного изображения
	free(data);
	return 0;
}


void init(void)
{
	//разрешить размытые тени
	glShadeModel(GL_SMOOTH);
	//цвет экрана черный
	glClearColor(0.0, 0.0, 0.0, 0.0);
	//разрешить текстуры
	glEnable(GL_TEXTURE_2D);
	//загрузка текстуры из bmp 24 бит
	LoadTexture(1, "01.bmp", 316, 316);
	LoadTexture(2, "02.bmp", 316, 316);
	LoadTexture(3, "05.bmp", 316, 316);
	LoadTexture(4, "03.bmp", 316, 316);
	LoadTexture(5, "06.bmp", 316, 316);
	LoadTexture(6, "04.bmp", 316, 316);

	//разрешить отображение только лицевой стороны
	//отсекается всё, что сзади, то есть glCullFace(GL_BACK)
	glEnable(GL_CULL_FACE);
	//качественная коррекция перспективы
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void reshape(int w, int h)
{
	//если вы вручную меняеете размеры окна во время исполнения программы
	if (h == 0)h = 1;

	ratio = 1.0 * w / h;
	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the clipping volume
	gluPerspective(45, ratio, 1, 200);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0, 0.0, 10.0,  /* eye is at (0,0,5) */
		0.0, 0.0, 0.0,      /* center is at (0,0,0) */
		0.0, 1.0, 0.);      /* up is in positive Y direction */
}

void display(void)
{
	//очистка экрана
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//сброс матрицы
	glLoadIdentity();

	glPushMatrix();
	glTranslatef(0.0, 0.0, -7.0);

	//вращение куба
	glRotatef(xrot, 1.0, 0.0, 0.0);
	glRotatef(yrot, 0.0, 1.0, 0.0);
	glRotatef(zrot, 0.0, 0.0, 1.0);

	//рисуем куб
	drawCube();

	glPopMatrix();

	if (rotation)
	{
		xrot += 0.03f;
		yrot += 0.02f;
		zrot += 0.04f;
	}

	glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)// Create Keyboard Function
{
	switch (key)
	{
	case 27:	// When Escape Is Pressed...
		exit(0);	// Exit The Program
		break;		// Ready For Next Case
	default:	// Now Wrap It Up
		break;
	}
}

void arrow_keys(int a_keys, int x, int y)// Create Special Function(required for arrow keys)
{
	switch (a_keys)
	{
	case GLUT_KEY_F1:
		// Go Into Full Screen Mode CTRL + F1
		if (glutGetModifiers() == 0)glutFullScreen();
		// Go Into Window Mode ALT +F1
		if (glutGetModifiers() == GLUT_ACTIVE_ALT)glutReshapeWindow(width, height);
		break;
	case GLUT_KEY_F2:
		// автоматическое вращение
		rotation = !rotation;
		break;
		// When Up Arrow Is Pressed...	
	case GLUT_KEY_UP:
		xrot -= 2.0f;
		break;
	case GLUT_KEY_DOWN:
		xrot += 2.0f;
		break;
	case GLUT_KEY_LEFT:
		yrot -= 2.0f;
		break;
	case GLUT_KEY_RIGHT:
		yrot += 2.0f;
		break;
	default:
		break;
	}
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	//установка режима отображения
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	//начальная позиция окна
	glutInitWindowPosition(0, 0);
	//размеры окна
	glutInitWindowSize(width, height);
	//создание GLUT окна, argv[0] это заголовок окна
	glutCreateWindow("GLUT Custom .bmp Import");
	//инициализация
	init();
	//переход в полноэкранный режим сразу после запуска
	//glutFullScreen();
	//рисование в окне
	glutDisplayFunc(display);
	//изменение размеров окна
	glutReshapeFunc(reshape);
	//обработка клавиатуры
	glutKeyboardFunc(keyboard);
	//обработка небуквенных клавиш
	glutSpecialFunc(arrow_keys);
	//во время простоя выполняется функция display()
	glutIdleFunc(display);
	//initialize the Main Loop
	glutMainLoop();
}