#include "Kwadryka.h"

unsigned int Kwadryka::TwórzTablicęWerteksówŚciętegoStożka(CWerteks*& tablicaWerteksów, float promieńDolny, float promieńGórny, float położeniePodstawy, float wysokość, int liczbaSekcji)
{
	const int liczbaWerteksów = 2 * (liczbaSekcji + 1);
	const double przyrostKąta = 2 * M_PI / liczbaSekcji;
	const float r = 1, g = 1, b = 1, a = 1;

	tablicaWerteksów = new CWerteks[liczbaWerteksów];	

	for (int i = 0; i <= liczbaSekcji; i++) //ilość par musi być większa o 1 niż ilość sekcji, przy pełnym obrocie pierwsza i ostatnia są takie same
	{		
		double kąt = i * przyrostKąta;

		tablicaWerteksów[2 * i].x = promieńGórny*(float)cos(kąt);
		tablicaWerteksów[2 * i].y = promieńGórny*(float)sin(kąt);
		tablicaWerteksów[2 * i].z = położeniePodstawy + wysokość;
		tablicaWerteksów[2 * i].r = r;
		tablicaWerteksów[2 * i].g = g;
		tablicaWerteksów[2 * i].b = b;
		tablicaWerteksów[2 * i].a = a;

		tablicaWerteksów[2 * i + 1].x = promieńDolny*(float)cos(kąt);
		tablicaWerteksów[2 * i + 1].y = promieńDolny*(float)sin(kąt);
		tablicaWerteksów[2 * i + 1].z = położeniePodstawy;
		tablicaWerteksów[2 * i + 1].r = r;
		tablicaWerteksów[2 * i + 1].g = g;
		tablicaWerteksów[2 * i + 1].b = b;
		tablicaWerteksów[2 * i + 1].a = a;

		//obliczanie normalnej
		float a = promieńDolny - promieńGórny;
		float c = sqrt(a * a + wysokość * wysokość);
		float sinTheta = a / c;
		float cosTheta = wysokość / c;
		tablicaWerteksów[2 * i].nx = (float)(cos(kąt)*cosTheta);
		tablicaWerteksów[2 * i].ny = (float)(sin(kąt)*cosTheta);
		tablicaWerteksów[2 * i].nz = sinTheta;
		tablicaWerteksów[2 * i + 1].nx = tablicaWerteksów[2 * i].nx;
		tablicaWerteksów[2 * i + 1].ny = tablicaWerteksów[2 * i].ny;
		tablicaWerteksów[2 * i + 1].nz = tablicaWerteksów[2 * i].nz;

		//współrzędne teksturowania
		tablicaWerteksów[2 * i].s = (float)(1 - kąt / 2 / M_PI);
		tablicaWerteksów[2 * i].t = 0;
		tablicaWerteksów[2 * i + 1].s = (float)(1 - kąt / 2 / M_PI);
		tablicaWerteksów[2 * i + 1].t = 1;
	}

	return liczbaWerteksów;
}

unsigned int Kwadryka::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	if (liczbaPasm == 1)
	{
		return TwórzTablicęWerteksówŚciętegoStożka(werteksy, promieńDolny, promieńGórny, położeniePodstawy, wysokość, liczbaSekcji);
	}
	else //tylko sfera ma więcej niż jedno pasmo; tu lepiej byłoby użyć bufora indeksów
	{
		unsigned int całkowitaLiczbaWerteksów = liczbaWerteksówWPaśmie * liczbaPasm;
		const float promień = promieńDolny;
		werteksy = new CWerteks[całkowitaLiczbaWerteksów];

		double przyrostKątaTheta = M_PI / liczbaPasm;
		for (int i = 0; i < liczbaPasm; i++)
		{
			double kątThetaGórny = i * przyrostKątaTheta;
			double kątThetaDolny = (i + 1) * przyrostKątaTheta;
			float wysokośćGórna = (float)(promień * cos(kątThetaGórny));
			float wysokośćDolna = (float)(promień * cos(kątThetaDolny));
			float _promieńGórny = (float)(promień * sin(kątThetaGórny));
			float _promieńDolny = (float)(promień * sin(kątThetaDolny));

			CWerteks* tablicaWerteksówPasma;
			unsigned int liczbaWerteksówWPaśmie = TwórzTablicęWerteksówŚciętegoStożka(
				tablicaWerteksówPasma, _promieńDolny, _promieńGórny, wysokośćDolna, wysokośćGórna - wysokośćDolna, liczbaSekcji);
			CWerteks* początekWerteksówPasma = werteksy + liczbaWerteksówWPaśmie * i;
			std::copy(tablicaWerteksówPasma, tablicaWerteksówPasma + liczbaWerteksówWPaśmie, początekWerteksówPasma);
			delete[] tablicaWerteksówPasma;
		}

		return całkowitaLiczbaWerteksów;
	}
}

void Kwadryka::Rysuj()
{
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	for (int i = 0; i < liczbaPasm; ++i)
	{
		glDrawArrays(GL_TRIANGLE_STRIP, i*liczbaWerteksówWPaśmie, liczbaWerteksówWPaśmie);
	}
	//glBindBuffer(GL_ARRAY_BUFFER, NULL);
	//glBindVertexArray(NULL);
}

//-------------------------------------------------------------------

unsigned int SferaZBuforemIndeksów::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	const unsigned int całkowitaLiczbaWerteksów = (liczbaSekcjiNaRównoleżnikach + 1) * (liczbaSekcjiNaPołudnikach + 1);
	werteksy = new CWerteks[całkowitaLiczbaWerteksów];

	const double przyrostKątaTheta = M_PI / liczbaSekcjiNaPołudnikach;
	const double przyrostKątaPhi = 2 * M_PI / liczbaSekcjiNaRównoleżnikach;

	const float r = 1, g = 1, b = 1, a = 1;

	for (unsigned int i = 0; i <= liczbaSekcjiNaPołudnikach; i++)
	{
		double kątTheta = i * przyrostKątaTheta;
		float _wysokość = (float)(promień * cos(kątTheta));
		float _promień = (float)(promień * sin(kątTheta));

		for (unsigned int j = 0; j <= liczbaSekcjiNaRównoleżnikach; j++)
		{
			double kątPhi = j*przyrostKątaPhi;
			int indeks = j + i*(liczbaSekcjiNaRównoleżnikach + 1);

			werteksy[indeks].x = _promień*(float)cos(kątPhi);
			werteksy[indeks].y = _promień*(float)sin(kątPhi);
			werteksy[indeks].z = _wysokość;
			werteksy[indeks].r = r;
			werteksy[indeks].g = g;
			werteksy[indeks].b = b;
			werteksy[indeks].a = 1;
			if (i != 0 && i != liczbaSekcjiNaPołudnikach)
			{
				werteksy[indeks].nx = werteksy[indeks].x / _promień;
				werteksy[indeks].ny = werteksy[indeks].y / _promień;
				werteksy[indeks].nz = werteksy[indeks].z / _promień;
			}
			else
			{
				werteksy[indeks].nx = 0;
				werteksy[indeks].ny = 0;
				werteksy[indeks].nz = werteksy[indeks].z / fabs(werteksy[indeks].z);
			}
			werteksy[indeks].s = (float)(1 - kątPhi / 2 / M_PI);
			werteksy[indeks].t = (float)(kątTheta / M_PI);
		}
	}

	return całkowitaLiczbaWerteksów;
}

unsigned int SferaZBuforemIndeksów::TwórzTablicęIndeksów(GLuint*& indeksy)
{
	const unsigned int liczbaIndeksówWPaśmie = 2 * (liczbaSekcjiNaRównoleżnikach + 1);
	const unsigned int całkowitaLiczbaIndeksów =
		liczbaIndeksówWPaśmie * liczbaSekcjiNaPołudnikach;
	indeksy = new GLuint[całkowitaLiczbaIndeksów];

	for (unsigned int i = 0; i < całkowitaLiczbaIndeksów / 2; i++)
	{
		indeksy[2 * i] = i;
		indeksy[2 * i + 1] = indeksy[2 * i] + (liczbaSekcjiNaRównoleżnikach + 1);
	}

	return całkowitaLiczbaIndeksów;
}
