// Тепер трикутник виводиться (була помилка: замість "glEnd;" треба писати "glEnd();" )
//

#include  <stdlib.h>
#define _USE_MATH_DEFINES 
#include  <math.h>
#include  <time.h>
#include  <string.h>
#include "gl/glut.h"

#pragma comment(lib, "freeglut.lib")

int xx, yy, cc;
int ButtonStatus = 0;
double* sizes;  // Масив діапазону розмірів точок
double* step;     // Масив кроків зростання розмірів

double* a;
int N = 0;
int Ncur = -1;//зхвачена точка

void init()
{
	glViewport(0, 0, 500, 500);//встановлює розміри області відображення
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glMatrixMode(GL_PROJECTION);//Задає режим проектування - ортографічна проекція
	glLoadIdentity();//Ініціалізація матриць проектування одиничними матрицями
	glOrtho(-250.0, 250.0, -250.0, 250.0, -1.0, 1.0);  //Задає параметри проектування (систему координат)
	glMatrixMode(GL_MODELVIEW);
}
void displayText(float x, float y, char* s) {
	int j = strlen(s);
	glRasterPos2f(x, y);
	for (int i = 0; i < j; i++) {
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, s[i]);
	}
}

void circle(int x0, int y0, int r) {
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < 360; i++) {
		float x = x0 + r * cos(i * M_PI / 180), y = y0 + r * sin(i * M_PI / 180);
		glVertex2f(x, y);
	}
	glEnd();
}

void display()
{
	char buf[80];

	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();
	glEnable(GL_POINT_SMOOTH);//точки згладженні. (якщо Disable - то квадратні)
	//glDisable(GL_POINT_SMOOTH);
	// Отримання діапазону розмірів точок та кроків зростання
	glGetDoublev(GL_POINT_SIZE_RANGE, sizes);
	glGetDoublev(GL_POINT_SIZE_GRANULARITY, step);

	//Формування графічної інформації
	for (int i = 1; i <= N; i++)
	{
		xx = (int)a[3 * i];
		yy = (int)a[3 * i + 1];
		cc = (int)a[3 * i + 2];
		glPointSize(cc);

		//Малювання примітивів
		glBegin(GL_POINTS);//Інші режими: GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON 
		glVertex3i(xx, yy, 0);// Вершина примітиву. В данному разі - точка.
		glEnd();
		_itoa_s(i, buf, 80, 10);
		displayText(xx + 16, yy + 20, buf);
	}

	//Задання кольору, розміру точки та формування точки
	glColor3ub(128, 0, 255);
	glPointSize(10);
	glBegin(GL_POINTS);
	glVertex2d(a[0], a[1]);
	glEnd();
	glColor3ub(255, 255, 255);

	circle(0, 0, 100);

	
	GLfloat BlueColor[3] = { 0,0,1 };
	glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0);//червоний
	glVertex3f(0.0, 0.0, 0.0);
	glColor3ub(0, 255, 0); // зелений
	glVertex3f(100.0, 0.0, 0.0);
	glColor3fv(BlueColor); //синій
	glVertex3f(100.0, 100.0, 0.0);
	glEnd();
	
	glFlush();

	//glutSwapBuffers();//Зміна графічних сторінок (корисно при анімації - проти "миготіння")
}

bool isin(int x, int y, int& n)
{
	n = -1;
	double eps = 10.0;
	for (int i = 0; i < N; i++)
		if (sqrt(((double)x - a[3 * i]) * (x - a[3 * i]) + (y - a[3 * i + 1]) * (y - a[3 * i + 1])) < eps)
		{
			n = i;
			return true;
		}
	return false;
}
void mouse(int button, int state, int x, int y)
{
	int n = -1;//індекс точки
	//Random r = new Random();
	srand(time(0));
	switch (button)
	{
	case GLUT_RIGHT_BUTTON:
		if (state == GLUT_DOWN)
		{
			//glutIdleFunc(spinDisplay); 
		}
		break;
	case GLUT_MIDDLE_BUTTON:
		if (state == GLUT_DOWN)
		{
			//glutIdleFunc(NULL); 
		}
		break;
	case GLUT_LEFT_BUTTON:
		if (state == GLUT_DOWN)
		{
			xx = x - 250;//Зв'язок координат миші та координат Opengl
			yy = 500 - y - 250;
			if (!isin(xx, yy, n))
			{
				//Нова точка
				cc = rand() % (int)sizes[1] + 1;
				a[3 * N] = (double)xx;
				a[3 * N + 1] = (double)yy;
				a[3 * N + 2] = cc;
				N++;
				glutPostRedisplay();
			}
			else
			{
				//Зхвачено вже існуючу точку
				ButtonStatus = 1;
				Ncur = n;
				//Поновлюємо координати
				a[3 * n] = (double)xx;
				a[3 * n + 1] = (double)yy;

			}
		}
		else
			if (state == GLUT_UP)
			{
				//Перетаскування завершено
				ButtonStatus = -1;
			}
		break;
	default:
		break;
	}
}
void MouseMotion(int x, int y)
{
	if (ButtonStatus == 1)
	{
		int xx, yy;
		xx = x - 250;//Зв'язок координат миші та координат Opengl
		yy = 500 - y - 250;
		a[3 * Ncur] = (double)xx;
		a[3 * Ncur + 1] = (double)yy;
		glutPostRedisplay();
	}
}
void keyb(unsigned char key, int x, int y)
{
	const unsigned char esc = 27;
	if (key == esc)
		exit(0);
}

void reshape(int w, int h)
{
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-250.0, 250.0, -250.0, 250.0, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


int main(int argc, char* argv[])
{
	sizes = new double[2];  // Масив діапазону розмірів точок
	step = new double[2];     // Масив кроків зростання розмірів
	a = new double[900];

	xx = 0; yy = 0; cc = 10;
	a[0] = 0; a[1] = 0; a[2] = 0;

	glutInit(&argc, argv);//ініціалізує бібліотеку GLUT

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	/* визначає, яку колірну модель слід використовувати: режим RGBA або режим індексації кольору.
	* Можна також визначити, чи прагнете ви працювати з буфером кадру вікна з одинарної або з подвійний буферизацією.
	* (Якщо ви працюєте в режимі індексації кольору, то ви, можливо, захочете завантажити деякі кольори в
	* таблицю компонентів кольору; для того щоб зробити це, скористайтеся командою glutSetColor().)
	* Нарешті, можна використовувати цю функцію для того, щоб вказати, що ви прагнете зв'язати з даним вікном
	* буфери глибини, трафарету й/або буфер-накопичувач. Наприклад, якщо ви бажаєте використовувати вікно з
	* подвійною буферизацією, колірною моделлю RGBA і буфером глибини, то для цього можна викликати розглянуту
	* функцію з наступними параметрами:
	* glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH).*/


	glutInitWindowSize(500, 500);//визначає розмір створюваного вікна в пікселях.
	glutInitWindowPosition(0, 0);//визначає місце розташування лівого верхнього кута створюваного вікна на екрані монітора.

	glutCreateWindow("hello");
	/* створює вікно з контекстом open Ця підпрограма повертає унікальний ідентифікатор для нового вікна.
	* Майте на увазі: доти, поки викликається підпрограма glutMainLoop(), це вікно ще не відображається на екрані.*/

	init();

	glutDisplayFunc(display);
	/* являє собою першу й найбільш важливу функцію зворотного виклику за подією.
	* Щоразу, коли бібліотека GLUT визначає, що вміст даного вікна має бути поновлений,
	* виконується функція зворотного виклику, зареєстрована підпрограмою glutDisplayFunc().
	* Тому ви повинні помістити всі підпрограми, які необхідні для перемальовування сцени,
	* у дану функцію зворотного виклику відображення.
	* Якщо ваша програма змінює вміст вікна, то іноді ви маєте викликати підпрограму glutPostRedisplay(void),
	* яка змушує підпрограму glutMainLoop() викликати зареєстровану функцію зворотного виклику відображення
	* при наступному зручному випадку
	*/

	glutReshapeFunc(reshape);//вказує на те, яке саме дія повинна бути виконана при зміні розміру вікна

	glutMouseFunc(mouse);//реєструє функцію, яка буде реагувати на події, що пов'язані з мишкою
	glutMotionFunc(MouseMotion);
	glutKeyboardFunc(keyb);//реєструє функцію, яка буде реагувати на події, що пов'язані з клавіатурою

	//glutIdleFunc(display);//реєструє функцію, що буде виконуватися постійно (у фоні)

	glutMainLoop();
	/* При цьому відображаються всі вікна, які були створені, і в цих вікнах тепер працює візуалізація.
	* Починається обробка подій, і викликається зареєстрована функція зворотного виклику відображення.
	* Увійшовши одного разу в цей цикл, з нього не виходять ніколи!*/

	return 0;
}

