#include "Aktor.h"

Aktor::Aktor()
:liczbaWerteksów(-1), MacierzŚwiata(Macierz4::Jednostkowa),
MateriałŚwiatłoOtoczenia(Wektor4(0.1f, 0.1f, 0.1f, 1)),
 MateriałŚwiatłoRozpraszane(Wektor4(1, 1, 1, 1)),
 MateriałŚwiatłoRozbłysku(Wektor4(0, 1, 0, 1)),
 MateriałWykładnikRozbłysku(100)
 {
 }

Aktor::~Aktor()
{
	UsuńBuforWerteksów();
}

void Aktor::Inicjuj(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor)
{
	InicjujBuforWerteksów();

	glVertexAttribPointer(atrybutPołożenie, CWerteks::liczbaWspółrzędnychPołożenia, GL_FLOAT, GL_FALSE, CWerteks::rozmiarWerteksu, 0);
	glEnableVertexAttribArray(atrybutPołożenie);
	glVertexAttribPointer(atrybutNormalna, CWerteks::liczbaWspółrzędnychNormalnej, GL_FLOAT, GL_FALSE, CWerteks::rozmiarWerteksu, (const GLvoid*)CWerteks::rozmiarWektoraPołożenia);
	glEnableVertexAttribArray(atrybutNormalna);
	glVertexAttribPointer(atrybutKolor, CWerteks::liczbaSkładowychKoloru, GL_FLOAT, GL_FALSE, CWerteks::rozmiarWerteksu, (const GLvoid*)(CWerteks::rozmiarWektoraPołożenia + CWerteks::rozmiarNormalnej));
	glEnableVertexAttribArray(atrybutKolor);
}

void Aktor::InicjujBuforWerteksów()
{
	//Vertex Array Object (VAO)
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	//Vertex Buffer Object (VBO)
	glGenBuffers(1, &vbo); //tworzy bufory
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	CWerteks* werteksy = NULL;
	liczbaWerteksów = TwórzTablicęWerteksów(werteksy);
	glBufferData(GL_ARRAY_BUFFER, liczbaWerteksów*sizeof(CWerteks), werteksy, GL_STATIC_DRAW);
	delete[] werteksy;
}

void Aktor::UsuńBuforWerteksów()
{
	glDeleteBuffers(1, &vbo);
	glDeleteVertexArrays(1, &vao);
}

void Aktor::Rysuj() //default implementation for triangle strip
{
	assert(liczbaWerteksów > 0);

	//bez bufora indeksów
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, liczbaWerteksów);
	//glBindBuffer(GL_ARRAY_BUFFER, NULL);
	//glBindVertexArray(NULL);
}

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

AktorZBuforemIndeksów::AktorZBuforemIndeksów()
:Aktor(), liczbaIndeksów(-1)
{
}

AktorZBuforemIndeksów::~AktorZBuforemIndeksów()
{
	//UsuńBuforWerteksów();
	Aktor::~Aktor();
	UsuńBuforIndeksów();
}

void AktorZBuforemIndeksów::Inicjuj(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor)
{
	Aktor::Inicjuj(atrybutPołożenie, atrybutNormalna, atrybutKolor);
	InicjujBuforIndeksów();
}

void AktorZBuforemIndeksów::InicjujBuforIndeksów()
{
	glGenBuffers(1, &vbo_indeksy);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_indeksy);

	GLuint* indeksy = NULL;
	liczbaIndeksów = TwórzTablicęIndeksów(indeksy);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, liczbaIndeksów*sizeof(GLuint), indeksy, GL_STATIC_DRAW);
	delete[] indeksy;
}

void AktorZBuforemIndeksów::UsuńBuforIndeksów()
{
	glDeleteBuffers(1, &vbo_indeksy);
}

void AktorZBuforemIndeksów::Rysuj()
{
	assert(liczbaIndeksów > 0);

	//z buforem indeksów
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo_indeksy);
	glDrawElements(GL_TRIANGLE_STRIP, liczbaIndeksów, GL_UNSIGNED_INT, 0);
	//glBindBuffer(GL_ARRAY_BUFFER, NULL);
	//glBindVertexArray(NULL);
}

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

Kwadrat::Kwadrat(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor, float długośćKrawędzi)
:Aktor(), długośćKrawędzi(długośćKrawędzi)
{
	Inicjuj(atrybutPołożenie, atrybutNormalna, atrybutKolor);
}

unsigned int Kwadrat::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	const float x0 = długośćKrawędzi/2.0f;
	const float y0 = długośćKrawędzi/2.0f;

	werteksy = new CWerteks[4];
	werteksy[0] = CWerteks(-x0, -y0, 0.0f, 0, 0, 1, 1, 1, 0, 1); //dolny lewy
	werteksy[1] = CWerteks(x0, -y0, 0.0f, 0, 0, 1, 1, 0, 1, 1); //dolny prawy
	werteksy[2] = CWerteks(-x0, y0, 0.0f, 0, 0, 1, 0, 1, 1, 1); //górny lewy
	werteksy[3] = CWerteks(x0, y0, 0.0f, 0, 0, 1, 1, 1, 1, 1);  //górny prawy

	return 4;
}

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

Trójkąt::Trójkąt(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor, float długośćPodstawy, float wysokość)
:Aktor(), długośćPodstawy(długośćPodstawy), wysokość(wysokość)
{
	Inicjuj(atrybutPołożenie, atrybutNormalna, atrybutKolor);
}

unsigned int Trójkąt::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	const float x0 = długośćPodstawy / 2.0f;
	const float y0 = wysokość / 2.0f;

	werteksy = new CWerteks[3];
	werteksy[0] = CWerteks(-x0, -y0, 0.0f, 0, 0, 1, 1, 0, 0, 1); //dolny lewy
	werteksy[1] = CWerteks(x0, -y0, 0.0f, 0, 0, 1, 0, 1, 0, 1); //dolny prawy
	werteksy[2] = CWerteks(0, y0, 0.0f, 0, 0, 1, 0, 0, 1, 1); //górny lewy

	return 3;
}

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

KwadratZBuforemIndeksów::KwadratZBuforemIndeksów(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor, float długośćKrawędzi)
:AktorZBuforemIndeksów(), długośćKrawędzi(długośćKrawędzi)
{
	Inicjuj(atrybutPołożenie, atrybutNormalna, atrybutKolor);
}

unsigned int KwadratZBuforemIndeksów::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	const float x0 = długośćKrawędzi / 2.0f;
	const float y0 = długośćKrawędzi / 2.0f;

	werteksy = new CWerteks[5];
	werteksy[0] = CWerteks(-x0, -y0, 0.0f, 0, 0, 1, 1, 0, 0, 1); //dolny lewy
	werteksy[1] = CWerteks(x0, -y0, 0.0f, 0, 0, 1, 0, 1, 0, 1); //dolny prawy
	werteksy[2] = CWerteks(0, y0, 0.0f, 0, 0, 1, 0, 0, 1, 1); //górny
	werteksy[3] = CWerteks(-x0, y0, 0.0f, 0, 0, 1, 0, 0, 1, 1); //górny lewy
	werteksy[4] = CWerteks(x0, y0, 0.0f, 0, 0, 1, 0, 0, 1, 1);  //górny prawy

	return 5;
}

unsigned int KwadratZBuforemIndeksów::TwórzTablicęIndeksów(GLubyte*& indeksy)
{
	indeksy = new GLubyte[4];
	indeksy[0] = 0;
	indeksy[1] = 1;
	indeksy[2] = 3;
	indeksy[3] = 4;

	return 4;
}

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

Prostopadłościan::Prostopadłościan(GLuint atrybutPołożenie, GLuint atrybutNormalna, GLuint atrybutKolor, float długośćKrawędziX, float długośćKrawędziY, float długośćKrawędziZ, bool koloruj)
:Aktor(), długośćKrawędziX(długośćKrawędziX), długośćKrawędziY(długośćKrawędziY), długośćKrawędziZ(długośćKrawędziZ), koloruj(koloruj)
{
	Inicjuj(atrybutPołożenie, atrybutNormalna, atrybutKolor);
}

unsigned int Prostopadłościan::TwórzTablicęWerteksów(CWerteks*& werteksy)
{
	const float x0 = długośćKrawędziX / 2.0f;
	const float y0 = długośćKrawędziY / 2.0f;
	const float z0 = długośćKrawędziZ / 2.0f;


	werteksy = new CWerteks[24];

	float r = 1.0f;
	float g = 1.0f;
	float b = 1.0f;

	if (koloruj) { r = 1.0f; g = 0.0f; b = 0.0f; }
	//tylnia
	werteksy[0] = CWerteks(x0, -y0, -z0, 0, 0, -1, r, g, b);
	werteksy[1] = CWerteks(-x0, -y0, -z0, 0, 0, -1, r, g, b);
	werteksy[2] = CWerteks(x0, y0, -z0, 0, 0, -1, r, g, b);
	werteksy[3] = CWerteks(-x0, y0, -z0, 0, 0, -1, r, g, b);
	//przednia
	werteksy[4] = CWerteks(-x0, -y0, z0, 0, 0, 1, r, g, b);
	werteksy[5] = CWerteks(x0, -y0, z0, 0, 0, 1, r, g, b);
	werteksy[6] = CWerteks(-x0, y0, z0, 0, 0, 1, r, g, b);
	werteksy[7] = CWerteks(x0, y0, z0, 0, 0, 1, r, g, b);

	if (koloruj) { r = 0.0f; g = 1.0f; b = 0.0f; }
	//prawa
	werteksy[8] = CWerteks(x0, -y0, z0, 1, 0, 0, r, g, b);
	werteksy[9] = CWerteks(x0, -y0, -z0, 1, 0, 0, r, g, b);
	werteksy[10] = CWerteks(x0, y0, z0, 1, 0, 0, r, g, b);
	werteksy[11] = CWerteks(x0, y0, -z0, 1, 0, 0, r, g, b);
	//lewa
	werteksy[12] = CWerteks(-x0, -y0, -z0, -1, 0, 0, r, g, b);
	werteksy[13] = CWerteks(-x0, -y0, z0, -1, 0, 0, r, g, b);
	werteksy[14] = CWerteks(-x0, y0, -z0, -1, 0, 0, r, g, b);
	werteksy[15] = CWerteks(-x0, y0, z0, -1, 0, 0, r, g, b);

	if (koloruj) { r = 0.0f; g = 0.0f; b = 1.0f; }
	//górna
	werteksy[16] = CWerteks(-x0, y0, z0, 0, 1, 0, r, g, b);
	werteksy[17] = CWerteks(x0, y0, z0, 0, 1, 0, r, g, b);
	werteksy[18] = CWerteks(-x0, y0, -z0, 0, 1, 0, r, g, b);
	werteksy[19] = CWerteks(x0, y0, -z0, 0, 1, 0, r, g, b);
	//dolna
	werteksy[20] = CWerteks(-x0, -y0, -z0, 0, -1, 0, r, g, b);
	werteksy[21] = CWerteks(x0, -y0, -z0, 0, -1, 0, r, g, b);
	werteksy[22] = CWerteks(-x0, -y0, z0, 0, -1, 0, r, g, b);
	werteksy[23] = CWerteks(x0, -y0, z0, 0, -1, 0, r, g, b);

	return 24;
}

void Prostopadłościan::Rysuj()
{
	//bez bufora indeksów
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	for (int i = 0; i < 6; ++i)
	{
		glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
	}
	//glBindBuffer(GL_ARRAY_BUFFER, NULL);
	//glBindVertexArray(NULL);
}
