#include <Windows.h>
#include <math.h>

//====== Подключение заголовков библиотек OpenGL
#include <GL\gl.h>
#include <GL\glu.h>
#include <GL\Glaux.h>

//====== Макроподстановка для изображения одной линии
#define Line(x1,y1,x2,y2)		\
	glBegin(GL_LINES);				\
		glVertex2d ((x1),(y1));		\
		glVertex2d ((x2),(y2));		\
	glEnd();

//====== Реакция на сообщение WM_PAINT
void __stdcall OnDraw()
{
	//====== Стираем буфер кадра (framebuffer)
	glClear (GL_COLOR_BUFFER_BIT);	
	//====== Выбираем черный цвет рисования
	glColor3f (0., 0., 0.);	
	
	//=== В 1-м ряду рисуем 3 линии с разной штриховкой
	glEnable (GL_LINE_STIPPLE);
	glLineWidth (2.);

	glLineStipple (1, 0x0101);		// dot
	Line (50., 125., 150., 125.);
	glLineStipple (1, 0x00FF);		// dash
	Line (150., 125., 250., 125.);
	glLineStipple (1, 0x1C47);		// dash/dot/dash
	Line (250., 125., 350., 125.);
	
	//====== Во 2-м ряду то же, но шире в 6 раз
	glLineWidth (6.);
	glLineStipple (1, 0x0101);		// dot
	Line (50., 100., 150., 100.);
	glLineStipple (1, 0x00FF);		// dash
	Line (150., 100., 250., 100.);
	glLineStipple (1, 0x1C47);		// dash/dot/dash
	Line (250., 100., 350., 100.);
	
	//=== Во 3-м ряду 7 линий являются частями
	//=== полосы (strip). Учетверенный узор не прерывается
	glLineWidth (2.);
	glLineStipple (4, 0x1C47);		// dash/dot/dash

	glBegin (GL_LINE_STRIP);
	for (int i = 1; i < 8; i++)
		glVertex2d (50.*i, 75.);
	glEnd();

	//=== Во 4-м ряду 6 независимых, отдельных линий
	//=== Тот же узор, но он каждый раз начинается заново
	for (i = 1;  i < 7; i++)
	{
		Line (50*i, 50, 50*(i+1), 50);
	}

	//====== Во 5-м ряду 1 линия с тем же узором
	glLineStipple (4, 0x1C47);		// dash/dot/dash
	Line (50., 25., 350., 25.);

	glDisable (GL_LINE_STIPPLE);
	glFlush ();
}

//====== Реакция на WM_SIZE
void __stdcall OnSize (int w, int h)
{
	glViewport (0, 0, (GLsizei) w, (GLsizei) h);
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity();

	//====== Режим ортографической проекции
	gluOrtho2D (0.0, double(w), 0.0, double(h));
}

//====== Настройки
void Init()
{
	//====== Цвет фона - белый
	glClearColor (1., 1., 1., 0.);
	//====== Нет интерполяции цвета при растеризации
	glShadeModel (GL_FLAT);	
}

void main()
{
	//=== Установка pixel-формата и подготовка окна OpenGL
	auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
	auxInitPosition (200, 200, 550, 250);
	auxInitWindow("My Stipple Test");
	
	Init();
	
	auxReshapeFunc (OnSize);	// Кого вызывать при WM_SIZE
	auxMainLoop(OnDraw);		// Кого вызывать при WM_PAINT
}


GLubyte gSpade[] = // Узор - пики
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x1f, 0xff, 0xff, 0xf8, 0x1f, 0x00, 0x00, 0xf8,
	0x01, 0xc0, 0x03, 0x80, 0x00, 0x70, 0x0e, 0x00,
	0x00, 0x20, 0x04, 0x00, 0x00, 0x30, 0x0c, 0x00,
	0x00, 0x10, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00,
	0x07, 0xc4, 0x23, 0xe0, 0x0f, 0xf8, 0x1f, 0xf0,
	0x38, 0x1c, 0x38, 0x1c, 0x30, 0x00, 0x00, 0x0c,
	0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06,
	0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06,
	0x60, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0c,
	0x30, 0x00, 0x00, 0x0c, 0x18, 0x00, 0x00, 0x18,
	0x0e, 0x00, 0x00, 0x70, 0x03, 0x00, 0x00, 0xc0,
	0x00, 0xc0, 0x03, 0x00, 0x00, 0x70, 0x0e, 0x00,
	0x00, 0x18, 0x18, 0x00, 0x00, 0x0c, 0x30, 0x00,
	0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00,
	0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
};

GLubyte gStrip[] = // Другой узор - полоса
{
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
	0x66, 0x66, 0x66, 0x66, 0x33, 0x33, 0x33, 0x33,
};



void __stdcall OnDraw()
{
	//====== Стираем окно
	glClear (GL_COLOR_BUFFER_BIT);
	//====== Цвет фона (синеватый)
	glColor3f (0.3f, 0.3f, 1.);
	
	//=== Рисуем сначала unstippled rectangle (без узора)
	//=== Rect - это тоже полигон
	glRectf (20., 20., 115., 120.);

	glColor3f (1., 0., 0.);				// Меняем цвет на красный
	glEnable (GL_POLYGON_STIPPLE);	// Включаем штриховку
	glPolygonStipple (gStrip);			// Задаем узор
	glRectf (120., 20., 215., 120.); // Рисуем

	glColor3f (0., 0., 0.);				// Меняем цвет на черный
	glPolygonStipple (gSpade);			// Меняем узор
	glRectf (220., 20., 315., 120.);

	glPolygonStipple (gStrip);			// Меняем узор
	glColor3f (0., 0.6f, 0.3f);
	glRectf (320., 20., 415., 120.);

	//=== Готовимся заполнить более сложный, невыпуклый
	//=== (non convex) полигон
	glPolygonStipple (gSpade);
	glColor3d (0.6, 0.f, 0.3f);

	//====== Шесть вершин по три координаты
	float c[6][3] =
	{
		420.,120.,0.,
		420.,70.,0.,
		470.,20.,0.,
		520., 70.,0.,
		520.,120.,0.,
		470.,100.,0.
	};

	//=== Здесь мы специально выбираем non convex полигон,
	//=== чтобы увидеть как плохо с ним обходится OpenGL
	glBegin(GL_POLYGON);
		for (int i=0; i<6; i++)
			glVertex3fv(c[i]);
	glEnd();
	glDisable (GL_POLYGON_STIPPLE);
	glFlush ();
}



void __stdcall OnDraw()
{
	glClear (GL_COLOR_BUFFER_BIT);
	glColor3d (1., 0.4, 1.);
	
	//=== 2 угла, характеризующие звезду и
	//=== 2 характерные точки
	double	pi = 4. * atan(1.),
			a1 = pi / 10.,	a2 = 3. * a1,
			x1 = cos(a1),		y1 = sin(a1),	
			x2 = cos(a2),		y2 = sin(a2);
	
	//=== Мировые координаты вершин нормированной звезды
	double c[5][3] =	
	{
		 0.,  1., 0.,
		-x2, -y2, 0.,
		 x1,  y1, 0.,
		-x1,  y1, 0.,
		 x2, -y2, 0.,
	};
	
	//====== Оконные координаты
	for (int i=0; i<5; i++)
	{
		c[i][0] = 250 + 100*c[i][0];
		c[i][1] = 100 + 100*c[i][1];
	}

	//=== Режим заполнения полигона - скелетный
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	//=== Задаем вершины полигона
	glBegin(GL_POLYGON);
		for (i=0; i<5; i++)
			glVertex3dv(c[i]);
	glEnd();
	
	glFlush();
}



void __stdcall OnDraw()
{
	glClear (GL_COLOR_BUFFER_BIT);
	glColor3d (1., 0.4, 1.);
	
	//====== Вогнутый шестиугольник, но мы зададим его
	//====== в виде двух четырехугольников
	float c[6][3] = 
	{
		200.,200.,0.,
		200.,100.,0.,
		250.,20.,0.,
		300.,100.,0.,
		300.,200.,0.,
		250.,100.,0.,
	};

	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glBegin(GL_QUADS);
		glVertex3fv(c[5]);
		glVertex3fv(c[0]);
		glVertex3fv(c[1]);
		glVertex3fv(c[2]);
		glVertex3fv(c[5]);
		glVertex3fv(c[2]);
		glVertex3fv(c[3]);
		glVertex3fv(c[4]);
	glEnd();

	glFlush ();
}



//====== Углы поворотов изображения вокруг осей X и Y
double gdAngleX, gdAngleY;
//====== Сдвиги вдоль координат
double gdTransX, gdTransY, gdTransZ = -4.;



void __stdcall OnDraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//=== Будем пользоваться услугами матрицы моделирования
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();

	//=== Задаем смещение координат точек будущих примитивов
	glTranslated(gdTransX, gdTransY, gdTransZ);

	//=== Задаем вращение координат точек будущих примитивов
	glRotated(gdAngleY, 0.,1.,0.);
	glRotated(gdAngleX, 1.,0.,0.);

	//====== Координаты точек куба (центр его в нуле)
	static float v[8][3] =
	{
		-1,   1., -1.,	// 4 точки задней грани задаются
		 1.,  1., -1.,	// в порядке против часовой стрелки
		 1., -1., -1.,
		-1,  -1., -1.,
		-1,   1.,  1.,	// 4 фронтальные точки
		-1., -1.,  1.,
		 1., -1.,  1.,
		 1,   1.,  1.
	};
	
	//====== 6 нормалей для 6-ти граней куба
	static double norm[6][3] =
	{
		0.,  0., -1.,		// Rear
		0.,  0.,  1.,		// Front
		-1., 0.,  0.,		// Left
		1.,  0.,  0.,		// Right
		0.,  1.,  0.,		// Top
		0., -1.,  0.		// Bottom
	};

	//====== Индексы вершин граней
	static GLuint id[6][4] =
	{
		0,1,2,3,	// Rear (обход CCW - counterclockwise)
		4,5,6,7,	// Front
		0,3,5,4,	// Left
		7,6,2,1,	// Right
		0,4,7,1,	// Top
		5,3,2,6,	// Bottom
	};

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glColor3d (1., 0.4, 1.);
	glBegin(GL_QUADS);

	//====== Долго готовились - быстро рисуем
	for (int i = 0; i < 6; i++)
	{
		glNormal3dv(norm[i]);

		for (int j = 0; j < 4; j++) 
			glVertex3fv(v[id[i][j]]);
	}
	glEnd();
	glFlush ();
}



glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);



int Lights;
glGetIntegerv(GL_MAX_LIGHTS, &Lights);
__asm nop



auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSELOC, OnLMouseMove);
auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSELOC, OnRMouseMove);
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, OnButtonDown);
auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN, OnButtonDown);



static void __stdcall OnButtonDown(AUX_EVENTREC *pEvent)
{
	//====== Запоминаем координаты мыши
	giX = pEvent->data[AUX_MOUSEX];
	giY = pEvent->data[AUX_MOUSEY];
}

static void __stdcall OnLMouseMove(AUX_EVENTREC *pEvent)
{
	//====== Узнаем текущие координаты
	int x = pEvent->data[AUX_MOUSEX];
	int y = pEvent->data[AUX_MOUSEY];

	//====== Изменяем углы поворота пропорционально
	//====== смещению мыши
	gdAngleX += (y - giY)/10.f;
	gdAngleY += (x - giX)/10.f;

	//====== Запоминаем координаты мыши
	giX = x;
	giY = y;
}

static void __stdcall OnRMouseMove(AUX_EVENTREC *pEvent)
{
	int x = pEvent->data[AUX_MOUSEX];
	int y = pEvent->data[AUX_MOUSEY];

	//====== На сколько удалить или приблизить
	double dx = (x - giX)/200.f;
	double dy = (y - giY)/200.f;

	//====== Удаляем или приближаем
	gdTransZ += (dx + dy)/2.f;

	//====== Запоминаем координаты мыши
	giX = x;
	giY = y;
}



	short x = pEvent->data[AUX_MOUSEX];
	short y = pEvent->data[AUX_MOUSEY];



	auxKeyFunc(AUX_DOWN, KeyDown);
	auxKeyFunc(AUX_UP, KeyUp);
	auxKeyFunc(AUX_LEFT, KeyLeft);
	auxKeyFunc(AUX_RIGHT, KeyRight);



void __stdcall KeyDown()
{
	gdTransY -= 0.1;			// Сдвигаем изображение вниз
}

void __stdcall KeyUp()
{
	gdTransY += 0.1;			// Сдвигаем изображение вверх
}

void __stdcall KeyLeft()
{
	gdTransX -= 0.1; 		// Сдвигаем изображение влево
}

void __stdcall KeyRight()
{
	gdTransX += 0.1;			// Сдвигаем изображение вправо
}



void DrawScene()
{
	//====== Создаем новый список команд OpenGL
	glNewList(1,GL_COMPILE);
		//====== Сюда поместите код, рисующий куб,
		//====== начиная со строки
		static float v[8][3] =
			. . . . . . .
		//====== и заканчивая 
		for (int j = 0; j < 4; j++) 
			glVertex3fv(v[id[i][j]]);
		}
		glEnd();
	glEndList();
}



void __stdcall OnDraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();
	glTranslated(gdTransX, gdTransY, gdTransZ);
	glRotated(gdAngleY, 0.,1.,0.);
	glRotated(gdAngleX, 1.,0.,0.);

	//====== Воспроизводим команды из списка 1
	glCallList(1);

	auxSwapBuffers();
}



void Init()
{
	glClearColor (1., 1., 1., 0.);
	//====== Включаем интерполяцию цветов полигона
	glShadeModel (GL_SMOOTH);

	glEnable(GL_DEPTH_TEST);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_COLOR_MATERIAL);

	//====== Готовим сцену
	DrawScene();
}



glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		
glBegin(GL_QUADS);

//====== Обновляем генератор случайных чисел
srand(time(0));

//====== 6 граней куба
for (int i = 0; i < 6; i++)
{
	glNormal3dv(norm[i]);

	//====== 4 вершины одной грани
	for (int j = 0; j < 4; j++)
	{
		//====== Задаем различные цвета
		glColor3d (rand()%10/10.,
					rand()%10/10., rand()%10/10.);
		glVertex3fv(v[id[i][j]]);
	}		
}
glEnd();
glEndList();



void DrawScene()
{
	static double
		//====== 2 характерные точки
		angle = 3. * atan(1.)/2.5,
		V = cos(angle),
		W = sin(angle),

		//====== 12 вершин икосаэдра (координаты x,y,z)
		v[12][3] =
		{
			{-V,0.,W}, {V,0.,W},  {-V,0.,-W},
			{V,0.,-W}, {0.,W,V},  {0.,W,-V},
			{0.,-W,V}, {0.,-W,-V},{W,V,0.},
			{-W,V,0.}, {W,-V,0.}, {-W,-V,0.}
		};

	//=== 20 граней икосаэдра, заданные индексами вершин
	static GLuint id[20][3] =
	{
		{0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8},
		{8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7},
		{7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1},
		{6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2}
	};

	//====== Начинаем формировать список команд
	glNewList(1,GL_COMPILE);
	//====== Выбираем текущий цвет рисования
	glColor3d (1., 0.4, 1.);
	glBegin(GL_TRIANGLES);

	for (int i = 0; i < 20; i++)
	{
		//====== Грубый подход к вычислению нормалей
		glNormal3dv(v[id[i][0]]);
		glVertex3dv(v[id[i][0]]);
		
		glNormal3dv(v[id[i][1]]);
		glVertex3dv(v[id[i][1]]);
		
		glNormal3dv(v[id[i][2]]);
		glVertex3dv(v[id[i][2]]);
	}

	glEnd();
	//====== Конец списка команд
	glEndList();
}



//=== Нормирование вектора нормали (или любого другого)
void Scale(double v[3])
{
	double d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
	if (d == 0.)
	{
		MessageBox(0,"Zero length vector","Error",MB_OK);
		return;
	}
	v[0] /= d; v[1] /= d; v[2] /= d;
}

void getNorm(double v1[3], double v2[3], double out[3])
{
	//====== Вычисляем координаты вектора нормали
	//====== по формулам векторного произведения
	out[0] = v1[1]*v2[2] - v1[2]*v2[1];
	out[1] = v1[2]*v2[0] - v1[0]*v2[2];
	out[2] = v1[0]*v2[1] - v1[1]*v2[0];
	Scale(out);
}



void DrawScene()
{

	static double	
		angle = 3. * atan(1.)/2.5,
		V = cos(angle),
		W = sin(angle),
 
		v[12][3] =
		{
			{-V,0.,W}, {V,0.,W},  {-V,0.,-W},
			{V,0.,-W}, {0.,W,V},  {0.,W,-V},
			{0.,-W,V}, {0.,-W,-V},{W,V,0.},
			{-W,V,0.}, {W,-V,0.}, {-W,-V,0.}
		};

	static GLuint id[20][3] =
	{
		{0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8},
		{8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7},
		{7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1},
		{6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2}
	};


	glNewList(1,GL_COMPILE);
	glColor3d (1., 0.4, 1.);
	glBegin(GL_TRIANGLES);

	for (int i = 0; i < 20; i++)
	{
		double d1[3], d2[3], norm[3];
		for (int j = 0; j < 3; j++)
		{
			d1[j] = v[id[i][0]] [j] - v[id[i][1]] [j];
			d2[j] = v[id[i][1]] [j] - v[id[i][2]] [j];
		}
		//====== Вычисление и масштабирование нормали
		getNorm(d1, d2, norm);
		glNormal3dv(norm);

		glVertex3dv(v[id[i][0]]);
		glVertex3dv(v[id[i][1]]);
		glVertex3dv(v[id[i][2]]);
	}

	glEnd();
	glEndList();
}



//=== Команды OpenGL для изображения одного треугольника
void setTria(double *v1, double *v2, double *v3)
{
	glBegin(GL_TRIANGLES);
		//====== Нормаль и вершина задаются одним вектором
		glNormal3dv(v1);
		glVertex3dv(v1);
		glNormal3dv(v2);
		glVertex3dv(v2);
		glNormal3dv(v3);
		glVertex3dv(v3);
	glEnd();
}

//====== Генерация внутренних треугольников
void Split(double *v1, double *v2, double *v3)
{
	//====== Промежуточные вершины
	double v12[3], v23[3], v31[3];

	for (int i = 0; i < 3; i++)
	{
		//====== Можно не делить пополам,
		//====== так как будем нормировать
		v12[i] = v1[i]+v2[i];
		v23[i] = v2[i]+v3[i];
		v31[i] = v3[i]+v1[i];
	}
	//====== Нормируем три новые вершины
	Scale(v12);
	Scale(v23);
	Scale(v31);
	//====== и рисуем четыре треугольника
	setTria(v1, v12, v31);
	setTria(v2, v23, v12);
	setTria(v3, v31, v23);
	setTria(v12,v23, v31);
}



void DrawScene()
{
	static double	
		angle = 3. * atan(1.)/2.5,
		V = cos(angle),
		W = sin(angle),

		v[12][3] =
		{
			{-V,0.,W}, {V,0.,W},  {-V,0.,-W},
			{V,0.,-W}, {0.,W,V},  {0.,W,-V},
			{0.,-W,V}, {0.,-W,-V},{W,V,0.},
			{-W,V,0.}, {W,-V,0.}, {-W,-V,0.}
		};

	static GLuint id[20][3] =
	{
		{0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8},
		{8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7},
		{7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1},
		{6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2}
	};

	glNewList(1,GL_COMPILE);
	glColor3d (1., 0.4, 1.);
	glBegin(GL_TRIANGLES);

	for (int i = 0; i < 20; i++) 
		Split (v[id[i][0]], v[id[i][1]], v[id[i][2]]); 

	glEnd();
	glEndList();
}



void __stdcall KeyN()
{
	//====== Изменяем способ вычисления нормалей
	gbSmooth = !gbSmooth;
	//====== Заново создаем список команд
	DrawScene();
}



void setTria(double *v1, double *v2, double *v3)
{
	glBegin(GL_TRIANGLES);
	//====== Если выбран способ точного вычисления нормали
	if (!gbSmooth)
	{
		//====== Правая тройка векторов
		double d1[3], d2[3], norm[3];

		//====== Вычисляем координаты векторов
		//====== двух сторон треугольника
		for (int j = 0; j < 3; j++)
		{
			d1[j] = v1[j] - v2[j];
			d2[j] = v2[j] - v3[j];
		}
		//====== Вычисляем нормаль к плоскости
		//====== треугольника со сторонами d1 и d2
		getNorm(d1, d2, norm);
		glNormal3dv(norm);
		glVertex3dv(v1);
		glVertex3dv(v2);
		glVertex3dv(v3);
	}
	else
	{
		//=== Неточное (приближенное) задание нормали
		glNormal3dv(v1);
		glVertex3dv(v1);
		glNormal3dv(v2);
		glVertex3dv(v2);
		glNormal3dv(v3);
		glVertex3dv(v3);
	}
	glEnd();
}



void Split(double *v1, double *v2, double *v3,	long depth)
{
	double v12[3], v23[3], v31[3];

	if (depth == 0)
	{
		//====== Рисование наименьших треугольников
		setTria(v1, v2, v3);
		//====== и выход из цепи рекурсивных вызовов
		return;
	}

	//====== Разбиение треугольника
	for (int i = 0; i < 3; i++)
	{
		v12[i] = v1[i]+v2[i];
		v23[i] = v2[i]+v3[i];
		v31[i] = v3[i]+v1[i];
	}

	//====== Дотягивание до сферы
	Scale(v12);
	Scale(v23);
	Scale(v31);
	//====== Рекурсивное разбиение на
	//====== четыре внутренних треугольника
	Split(v1, v12, v31, depth-1);
	Split(v2, v23, v12, depth-1);
	Split(v3, v31, v23, depth-1);
	Split(v12, v23, v31, depth-1);
}



void __stdcall KeySpace()
{
	//====== Флаг роста числа разбиений
	static bool bGrow = true;
	
	//====== Продолжаем разбивать до глубины 4
	if (bGrow && giDepth < 4)
	{
		giDepth += 1;
	}
	//====== Смена знака при глубине 4
	else if (giDepth > 0)
	{
		bGrow = false;
		giDepth -= 1;
	}
	//====== Смена знака при глубине 0
	else
	{
		bGrow = true;
		giDepth += 1;
	}

	DrawScene();
}



//====== Если существует 1-й список,
if (glIsList(1))
		//====== то освобождаем память
		glDeleteLists(1,1);



#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>

const UINT gnRings = 40;		// Количество колец (широта)
const UINT gnSects = 40;		// Количество секций (долгота)

//====== Общее количество треугольников
const UINT gnTria = (gnRings+1) * gnSects * 2;

//====== Общее количество вершин
const UINT gnVert = (gnRings+1) * gnSects + 2;

//====== Два цвета вершин
const COLORREF gClr1 = RGB(0, 255, 0);
const COLORREF gClr2 = RGB(0, 0, 255);

const double gRad = 1.5;			// Радиус сферы
const double gMax = 5.;			// Амплитуда сдвига
const double PI = atan(1.)*4.; // Число пи



//====== Точка 3D-пространства
class CPoint3D	
{
public:
	float x, y, z;	// Координаты точки

	//====== Конструктор по умолчанию
	CPoint3D () { x = y = z = 0; }
	//====== Конструктор с параметрами
	CPoint3D (double c1, double c2, float c3)
	{
		x = float(c1);
		z = float(c2);
		y = float(c3);
	}

	//====== Операция присвоения
	CPoint3D& operator=(const CPoint3D& pt)
	{
		x = pt.x;
		z = pt.z;
		y = pt.y;
		return *this;
	}
	
	//====== Операция сдвига в пространстве
	CPoint3D& operator+=(const CPoint3D& pt)
	{
		x += pt.x;
		y += pt.y;
		z += pt.z;
		return *this;
	}	

	//====== Конструктор копирования
	CPoint3D (const CPoint3D& pt)
	{
		*this = pt;
	}
};



//====== Данные о вершине геометрического примитива
struct VERT
{
	CPoint3D v;	// Координаты вершины
	CPoint3D n;	// Координаты нормали
	DWORD c;		// Цвет вершины
};



struct TRIA
{
	//====== Индексы трех вершин треугольника,
	//====== выбираемых из массива вершин типа VERT
	//====== Порядок обхода - против часовой стрелки
	int i1;
	int i2;
	int i3;
};



//====== Вектор углов вращения вокруг трех осей
CPoint3D gSpin;
//====== Вектор случайной девиации вектора gSpin
CPoint3D gShift;



inline double Rand(double x)
{
	//====== Случайное число в диапазоне (-x, x)
	return x - (x + x) * rand() / RAND_MAX;
}



void __stdcall OnDraw()
{
	glClear(GL_COLOR_BUFFER_BIT);
	//=== Сейчас текущей является матрица моделирования
	glLoadIdentity();

	//====== Учет вращения	
	glRotated(gSpin.x, 1., 0,  0.);
	glRotated(gSpin.y, 0., 1., 0.);
	glRotated(gSpin.z, 0., 0., 1.);

	//====== Вызов списка рисующих команд	
	glCallList(1);
	
	//====== Подготовка следующей позиции сферы
	gSpin += gShift;
	
	//====== Смена буферов
	auxSwapBuffers();
}



void Init()
{
	//=== Цвет фона (на сей раз традиционно черный)
	glClearColor (0., 0., 0., 0.);

	//====== Включаемаем необходимость учета света
	glEnable(GL_LIGHTING);
	//====== Включаемаем первый и единственный источник света
	glEnable(GL_LIGHT0);
	//====== Включаем учет цвета материала объекта
	glEnable(GL_COLOR_MATERIAL);

	// Вектор для задания различных параметров освещенности
	float v[4] =
	{
		0.05f, 0.05f, 0.05f, 1.f
	};

	//=== Сначала задаем величину окружающей освещенности
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, v);

	//====== Изменяем вектор
	v[0] = 0.9f;
	v[1] = 0.9f;
	v[2] = 0.9f;

	//====== Задаем величину диффузной освещенности
	glLightfv(GL_LIGHT0, GL_DIFFUSE, v);

	//======= Изменяем вектор
	v[0] = 0.6f;
	v[1] = 0.6f;
	v[2] = 0.6f;

	//====== Задаем отражающие свойства материчала
	glMaterialfv(GL_FRONT, GL_SPECULAR, v);

	//====== Задаем степень блесткости материала
	glMateriali(GL_FRONT, GL_SHININESS, 40);

	//====== Изменяем вектор
	v[0] = 0.f;
	v[1] = 0.f;
	v[2] = 1.f;
	v[3] = 0.f;

	//====== Задаем позицию источника света
	glLightfv(GL_LIGHT0, GL_POSITION, v);

	//====== Переключаемся на матрицу проекции
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//====== Задаем тип проекции
	gluPerspective(45, 1, .01, 15);

	//=== Сдвигаем точку наблюдения, отодвигаясь от
	//=== центра сцены в направлении оси z на 8 единиц
	gluLookAt(0, 0, 8, 0, 0, 0, 0, 1, 0);

	//====== Переключаемся на матрицу моделирования
	glMatrixMode(GL_MODELVIEW);

	//====== Включаем механизм учета ориентации полигонов
	glEnable(GL_CULL_FACE);
	//====== Не учитываем обратные поверхности полигонов
	glCullFace(GL_BACK);
	
	//====== Настройка OpenGL на использование массивов
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	
	//====== Захват памяти под динамические массивы
	VERT *Vert = new VERT[gnVert];
	TRIA *Tria = new TRIA[gnTria];

	//====== Создание изображения
	Sphere(Vert, Tria);
	
	//====== Задание адресов трех массивов (вершин,
	//====== нормалей и цветов),
	//====== а также шага перемещения по ним
	glVertexPointer(3, GL_FLOAT, sizeof(VERT), &Vert->v);
	glNormalPointer(GL_FLOAT, sizeof(VERT), &Vert->n);
	glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERT),
													&Vert->c);
	
	srand(time(0));		// Подготовка ГСЧ
	gShift = CPoint3D (Rand(gMax),Rand(gMax),Rand(gMax));

	//====== Формирование списка рисующих команд
	glNewList(1, GL_COMPILE);
		glDrawElements(GL_TRIANGLES, gnTria*3,
							GL_UNSIGNED_INT, Tria);
	glEndList();

	//== Освобождение памяти, так как список сформирован
	delete [] Vert;
	delete [] Tria;
}



void Sphere(VERT *v, TRIA* t)
{
	//====== Формирование массива вершин
	//====== Северный полюс
	v[0].v = CPoint3D (0, gRad, 0);
	v[0].n = CPoint3D (0, 1, 0);
	v[0].c = gClr2;

	//====== Индекс последней вершины (на южном полюсе)
	UINT last = gnVert - 1;
	//====== Южный полюс
	v[last].v = CPoint3D (0, -gRad, 0);
	v[last].n = CPoint3D (0, -1, 0);
	v[last].c = gnVert & 1 ? gClr2 : gClr1;

	//====== Подготовка констант
	double	da = PI / (gnRings + 2.),
			db = 2. * PI / gnSects,
			af = PI - da/2.,
			bf = 2. * PI - db/2.;

	//=== Индекс вершины, следующей за северным полюсом
	UINT n = 1;
	//=== Цикл по широтам
	for (double a = da;  a < af;  a += da)
	{
		//=== Координата y постоянна для всего кольца
		double	y  = gRad * cos(a),
				//====== Вспомогательная точка
				xz = gRad * sin(a);

		//====== Цикл по секциям (долгота)
		for (double b = 0.; b < bf; n++, b += db)
		{
			// Координаты проекции в экваториальной плоскости
			double	x = xz * sin(b),
					z = xz * cos(b);

			//====== Вершина, нормаль и цвет
			v[n].v = CPoint3D (x, y, z);
			v[n].n = CPoint3D (x / gRad, y / gRad, z / gRad);
			v[n].c = n & 1 ? gClr1 : gClr2;
		}
	}

	//====== Формирование массива индексов
	//====== Треугольники вблизи полюсов
	for (n = 0; n < gnSects; n++)
	{
		//====== Индекс общей вершины (северный полюс)
		t[n].i1 = 0;
		//====== Индекс текущей вершины
		t[n].i2 = n + 1;
		//====== Замыкание
		t[n].i3 = n == gnSects - 1 ? 1 : n + 2;
		//====== Индекс общей вершины (южный полюс)
		t[gnTria-gnSects+n].i1 = gnVert - 1;
		t[gnTria-gnSects+n].i2 = gnVert - 2 - n;
		t[gnTria-gnSects+n].i3 = gnVert - 2
								- ((1 + n) % gnSects);
	}
	
	//====== Треугольники разбиения колец
	//====== Вершина, следующая за полюсом
	int k = 1;

	//====== gnSects - номер следующего треугольника
	n = gnSects;
	for (UINT i = 0; i < gnRings; i++, k += gnSects)
	{
		for (UINT j = 0; j < gnSects; j++, n += 2)
		{
			//======= Индекс общей вершины
			t[n].i1 = k + j;
			//======= Индекс текущей вершины
			t[n].i2 = k + gnSects + j;
			//======= Замыкание
			t[n].i3 = k + gnSects + ((j + 1) % gnSects);
			//======= То же для второго треугольника
			t[n + 1].i1 = t[n].i1;
			t[n + 1].i2 = t[n].i3;
			t[n + 1].i3 = k + ((j + 1) % gnSects);
		}
	}
}



void __stdcall OnSize(GLsizei w, GLsizei h)
{
	glViewport(0, 0, w, h);
}

void main()
{
	auxInitDisplayMode(AUX_RGB | AUX_DOUBLE);
	auxInitPosition(10, 10, 512, 512);
	auxInitWindow("Vertex Array");

	Init();

	auxReshapeFunc(OnSize);
	auxIdleFunc(OnDraw);
	auxMainLoop(OnDraw);
}




