﻿//Kubik
//Реалізація ручної сборки кубіка Рубіка
//Обертання задньої грані представлено частково
//Обертання граней за допомогою клавіш 1-6, обертання кубіка за допомогою стрілок
//#include "stdafx.h"
#include<windows.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"freeglut.lib")
#pragma comment(lib,"glu32.lib") 
#include"gl/glut.h"
#include <math.h>
//float Trot=0;
//float Qrot=0;
void display(void);
void SpecKeyDown(int key, int x, int y);
void KeyDown(unsigned char key, int x, int y);
void mousefunction(int button, int state, int x, int y);
void MouseMotion(int x, int y);
//int alpha=300;
int rotate1 = 0, rotate = 0;
double spin = 0.0;
double alfa = 10,//15,
beta = 30;//30;
int ox = 0, oy = 0;
float matrix[16];

typedef
enum { TOP, BOTTOM, LEFT, RIGHT, FRONT, BACK } edge;

void  myReshape(GLsizei w, GLsizei h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60, (GLfloat)w / (GLfloat)h, 1, 1000.0);
	//glFrustum(1,-1,-1,1,4,10);
	//glOrtho(-500,500,-500,500,-1000,1000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslated(0, 0, -700);
	glRotated(alfa, 1, 0, 0);
	glRotated(beta, 0, 1, 0);

}

GLfloat white[] = { 1,1,1 };
GLfloat black[] = { 0,0,0 };
GLfloat red[] = { 1,0,0 };
GLfloat green[] = { 0,1,0 };
GLfloat blue[] = { 0,0,1 };
GLfloat mShininess[] = { 128 };


int top[3][3], bottom[3][3], left[3][3], right[3][3], back[3][3], front[3][3];

void init(void)
{
	glClearColor(0.5, 0.5, 0.75, 1.0);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	//glEnable (GL_NORMALIZE);
	glEnable(GL_COLOR_MATERIAL);
	glGetFloatv(GL_MODELVIEW_MATRIX, matrix);


	//glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, blue);
	//glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mShininess);
	//glEnable (GL_CULL_FACE);

	glEnable(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	//glShadeModel (GL_FLAT);

}

int main(int argc, char* argv[])
{
	int i, j, k, l;
	for (i = -1; i <= 1; i++)
		for (j = -1; j <= 1; j++)
		{
			top[i + 1][j + 1] = 1;
			bottom[i + 1][j + 1] = 2;
			left[i + 1][j + 1] = 3;
			right[i + 1][j + 1] = 4;
			front[i + 1][j + 1] = 5;
			back[i + 1][j + 1] = 6;
		}

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500, 500);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("KUBIK_SOLID");
	init();
	glutReshapeFunc(myReshape);
	glutKeyboardFunc(KeyDown);
	glutSpecialFunc(SpecKeyDown);
	glutMouseFunc(mousefunction);
	glutMotionFunc(MouseMotion);
	glutIdleFunc(display);
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

//#define N 50
double sqr(double x)
{
	return x * x;
}
void docolor(int i)
{
	switch (i)
	{
	case 1: glColor3f(0, 1, 1); break;//BACK;
	case 2: glColor3f(1, 0, 1); break;//FRONT;
	case 3: glColor3f(1, 0, 0); break;//TOP;
	case 4: glColor3f(0, 1, 0); break;//BOTTOM;
	case 5: glColor3f(1, 1, 0); break;//LEFT;
	case 6: glColor3f(0, 0, 1); break;//RIGHT;


	case 7: glColor3f(0, 0.5, 0.5); break;//BACK;
	case 8: glColor3f(0.5, 0, 0.5); break;//FRONT;
	case 9: glColor3f(0.5, 0, 0); break;//TOP;

	default:
		glColor3f(0.3, 0.3, 0.3);
	}
}

void drawkub(int x0, int y0, int z0, int d, int mode, int i, int j, int k)
{
	//z=0
	//if(k==-1) glColor3f(0,1,1);//BACK;
	if (k == -1) docolor(back[i + 1][j + 1]);//BACK;
	glBegin(mode);
	glNormal3f(0, 0, -1);
	glVertex3f(x0 - d, y0 - d, z0 - d);
	glVertex3f(x0 + d, y0 - d, z0 - d);
	glVertex3f(x0 + d, y0 + d, z0 - d);
	glVertex3f(x0 - d, y0 + d, z0 - d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

	//z=d
	//if(k==1) glColor3f(1,0,1);//FRONT;
	if (k == 1) docolor(front[i + 1][j + 1]);//FRONT;
	glBegin(mode);
	glNormal3f(0, 0, 1);
	glVertex3f(x0 - d, y0 - d, z0 + d);
	glVertex3f(x0 + d, y0 - d, z0 + d);
	glVertex3f(x0 + d, y0 + d, z0 + d);
	glVertex3f(x0 - d, y0 + d, z0 + d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

	//y=0
	//if(j==-1) glColor3f(1,0,0);//BOTTOM;
	if (j == -1) docolor(bottom[i + 1][k + 1]);//BOTTOM;
	glBegin(mode);
	glNormal3f(0, -1, 0);
	glVertex3f(x0 - d, y0 - d, z0 - d);
	glVertex3f(x0 + d, y0 - d, z0 - d);
	glVertex3f(x0 + d, y0 - d, z0 + d);
	glVertex3f(x0 - d, y0 - d, z0 + d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

	//y=d
	//if(j==1) glColor3f(0,1,0);//TOP;
	if (j == 1) docolor(top[i + 1][k + 1]);//TOP;
	glBegin(mode);
	glNormal3f(0, 1, 0);
	glVertex3f(x0 - d, y0 + d, z0 - d);
	glVertex3f(x0 + d, y0 + d, z0 - d);
	glVertex3f(x0 + d, y0 + d, z0 + d);
	glVertex3f(x0 - d, y0 + d, z0 + d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

	//x=0
	//if(i==-1) glColor3f(1,1,0);//LEFT;
	if (i == -1) docolor(left[j + 1][k + 1]);//LEFT;
	glBegin(mode);
	glNormal3f(-1, 0, 0);
	glVertex3f(x0 - d, y0 - d, z0 - d);
	glVertex3f(x0 - d, y0 + d, z0 - d);
	glVertex3f(x0 - d, y0 + d, z0 + d);
	glVertex3f(x0 - d, y0 - d, z0 + d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

	//x=d
	//if(i==1) glColor3f(0,0,1);//RIGHT;
	if (i == 1) docolor(right[j + 1][k + 1]);//RIGHT;
	glBegin(mode);
	glNormal3f(1, 0, 0);
	glVertex3f(x0 + d, y0 - d, z0 - d);
	glVertex3f(x0 + d, y0 + d, z0 - d);
	glVertex3f(x0 + d, y0 + d, z0 + d);
	glVertex3f(x0 + d, y0 - d, z0 + d);
	glEnd();
	glColor3f(0.3, 0.3, 0.3);

}
void dkr(int x0, int y0, int z0, int r)
{
	int i, j, k;
	if (rotate1 == 0)
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
	if (rotate1 == 1)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (i != 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 1, 0, 0);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (i == 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}
	if (rotate1 == 2)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (i != -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 1, 0, 0);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (i == -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}

	if (rotate1 == 3)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (j != 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 0, 1, 0);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (j == 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}
	if (rotate1 == 4)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (j != -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 0, 1, 0);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (j == -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}

	if (rotate1 == 5)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (k != 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 0, 0, 1);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (k == 1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}
	if (rotate1 == 6)
	{
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (k != -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPushMatrix();
		glRotated(spin / 10.0, 0, 0, 1);
		glColor3f(1, 0, 0);
		for (k = -1; k <= 1; k++)
			for (j = -1; j <= 1; j++)
				for (i = -1; i <= 1; i++)
					if (k == -1)
						drawkub(x0 + i * r, y0 + j * r, z0 + k * r, (r - 1) / 2, GL_QUADS, i, j, k);
		glPopMatrix();
	}



}


void light(void) {
	glLightfv(GL_LIGHT0, GL_SPECULAR, white);
	glLightfv(GL_LIGHT0, GL_AMBIENT, black);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
}


void display(void)
{
	int i, j, k;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
	glRotatef(alfa, 1, 0, 0);
	glRotatef(beta, 0, 1, 0);
	glColor3f(0.3, 0.3, 0.3);
	dkr(0, 0, 0, 90);
	//glPushMatrix();
	//glRotated(alfa, 0, 1, 0);
	//glRotated(beta, 0, 1, 0);
	//glColor3f(1, 0, 0);
	//glPopMatrix();
	if (rotate1 > 0)
	{
		spin += 1;
		if (spin == 90 * 10)
		{
			spin = 0;
			int temp[3], t;
			if (rotate1 == 1)
			{
				for (int j = 0; j < 3; j++)
					temp[j] = front[2][j];

				for (int j = 0; j < 3; j++)
					front[2][j] = top[2][2 - j];

				for (int j = 0; j < 3; j++)
					top[2][j] = back[2][j];

				for (int j = 0; j < 3; j++)
					back[2][j] = bottom[2][2 - j];

				for (int j = 0; j < 3; j++)
					bottom[2][j] = temp[j];


				t = right[0][0];
				right[0][0] = right[0][2];
				right[0][2] = right[2][2];
				right[2][2] = right[2][0];
				right[2][0] = t;

				t = right[1][0];
				right[1][0] = right[0][1];
				right[0][1] = right[1][2];
				right[1][2] = right[2][1];
				right[2][1] = t;
			}

			if (rotate1 == 2)
			{
				for (int j = 0; j < 3; j++)
					temp[j] = front[0][j];

				for (int j = 0; j < 3; j++)
					front[0][j] = top[0][2 - j];

				for (int j = 0; j < 3; j++)
					top[0][j] = back[0][j];

				for (int j = 0; j < 3; j++)
					back[0][j] = bottom[0][2 - j];

				for (int j = 0; j < 3; j++)
					bottom[0][j] = temp[j];


				t = left[0][0];
				left[0][0] = left[0][2];
				left[0][2] = left[2][2];
				left[2][2] = left[2][0];
				left[2][0] = t;

				t = left[1][0];
				left[1][0] = left[0][1];
				left[0][1] = left[1][2];
				left[1][2] = left[2][1];
				left[2][1] = t;

			}
			if (rotate1 == 3)
			{
				for (int j = 0; j < 3; j++)
					temp[j] = front[2 - j][2];

				for (int j = 0; j < 3; j++)
					front[j][2] = left[2][j];

				for (int j = 0; j < 3; j++)
					left[2][j] = back[2 - j][2];

				for (int j = 0; j < 3; j++)
					back[j][2] = right[2][j];

				for (int j = 0; j < 3; j++)
					right[2][j] = temp[j];


				t = top[0][0];
				top[0][0] = top[2][0];
				top[2][0] = top[2][2];
				top[2][2] = top[0][2];
				top[0][2] = t;

				t = top[1][0];
				top[1][0] = top[2][1];
				top[2][1] = top[1][2];
				top[1][2] = top[0][1];
				top[0][1] = t;
			}

			if (rotate1 == 4)
			{
				for (int j = 0; j < 3; j++)
					temp[j] = front[2 - j][0];

				for (int j = 0; j < 3; j++)
					front[j][0] = left[0][j];

				for (int j = 0; j < 3; j++)
					left[0][j] = back[2 - j][0];

				for (int j = 0; j < 3; j++)
					back[j][0] = right[0][j];

				for (int j = 0; j < 3; j++)
					right[0][j] = temp[j];


				t = bottom[0][0];
				bottom[0][0] = bottom[2][0];
				bottom[2][0] = bottom[2][2];
				bottom[2][2] = bottom[0][2];
				bottom[0][2] = t;

				t = bottom[1][0];
				bottom[1][0] = bottom[2][1];
				bottom[2][1] = bottom[1][2];
				bottom[1][2] = bottom[0][1];
				bottom[0][1] = t;
			}


			//front:clock-wise
			//top->left->bottom->right
			if (rotate1 == 5)
			{
				for (int j = 0; j < 3; j++)
					temp[j] = left[2 - j][2];

				for (int j = 0; j < 3; j++)
					left[j][2] = top[j][2];

				for (int j = 0; j < 3; j++)
					top[j][2] = right[2 - j][2];

				for (int j = 0; j < 3; j++)
					right[j][2] = bottom[j][2];

				for (int j = 0; j < 3; j++)
					bottom[j][2] = temp[j];


				t = front[0][0];
				front[0][0] = front[0][2];
				front[0][2] = front[2][2];
				front[2][2] = front[2][0];
				front[2][0] = t;

				t = front[1][0];
				front[1][0] = front[0][1];
				front[0][1] = front[1][2];
				front[1][2] = front[2][1];
				front[2][1] = t;
			}


			//back:
			//top->left->bottom->right
			if (rotate1 == 6)
			{
				//TODO
				//Зробіть самостійно
			}

			rotate1 = 0;
		}

	}

	glPopMatrix();
	glFlush();
	glutSwapBuffers();
}


void KeyDown(unsigned char key, int x, int y)
{
	//MessageBox(0,L"Up",L"Press",MB_ICONINFORMATION);
	if ((rotate1 == 0) && (key > '0') && (key < '7')) rotate1 = key - '0';
}
void SpecKeyDown(int key, int x, int y)
{
	//MessageBox(0,L"Up",L"Press",MB_ICONINFORMATION);
	if (key == GLUT_KEY_DOWN) alfa++;
	if (alfa == 360) alfa = 0;
	if (key == GLUT_KEY_UP) alfa--;
	if (alfa == -1) alfa = 359;

	if (key == GLUT_KEY_RIGHT) beta++;
	if (alfa == 360) beta = 0;
	if (key == GLUT_KEY_LEFT) beta--;
	if (alfa == -1) beta = 359;

}


void mousefunction(int button, int state, int x, int y)
{
	if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN))
	{
		ox = x; oy = y;
	}
	if (button == 3)//MOUSE_SCROLL_UP
	{
		glScaled(1.25, 1.25, 1.25);
		glutPostRedisplay();
	}
	else
		if (button == 4)//MOUSE_SCROLL_DOWN
		{
			glScaled(0.8, 0.8, 0.8);
			glutPostRedisplay();
		}

}
void MouseMotion(int x, int y)
{
	float x1, y1, z1;
	//v1*dx,+v2*dy,0
	//ortogon:v1*(-dy)+v2*dx
	x1 = (y - oy) * matrix[0] + (x - ox) * matrix[1];
	y1 = (y - oy) * matrix[4] + (x - ox) * matrix[5];
	z1 = (y - oy) * matrix[8] + (x - ox) * matrix[9];
	glTranslated(0.5, 0, 0.5);
	glRotatef((float)sqrt((x - ox) * (x - ox) + (y - oy) * (y - oy)), x1, y1, z1);
	glTranslated(-0.5f, 0, -0.5);
	ox = x; oy = y;
	glutPostRedisplay();

}



