#include "SpriteRenderer.h"
#include <iostream>

Core::SpriteRenderer::SpriteRenderer()
{
    this->initRenderData();
}

Core::SpriteRenderer::~SpriteRenderer()
{
    glDeleteVertexArrays(1, &this ->VAO);
    glDeleteBuffers(1, &this->VBO);
    glDeleteBuffers(1, &this->EBO);
}
void Core::SpriteRenderer::DrawHUDBar(const glm::vec3 color, const glm::mat4 modelMatrix, const float progress, GLuint program) {
	
	Spaceship* spaceship = Spaceship::getInstance();

	glm::mat4 viewProjectionMatrix = Core::createPerspectiveMatrix() * spaceship->createCameraMatrixForHUDBar();

	// Kombinuj macierze transformacji
	glm::mat4 transformation = viewProjectionMatrix * modelMatrix;

	// Przeka¿ macierze do shadera
	glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, glm::value_ptr(transformation));
	glUniformMatrix4fv(glGetUniformLocation(program, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
	glUniform3fv(glGetUniformLocation(program, "activeColor"), 1, glm::value_ptr(color));
	glUniform1f(glGetUniformLocation(program, "progress"), progress);

	glBindVertexArray(this->VAO);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	glBindVertexArray(0);
};
void Core::SpriteRenderer::DrawSpriteBar(const glm::vec3 color, const glm::mat4 modelMatrix,const float progress, GLuint program) {

	Spaceship* spaceship = Spaceship::getInstance();

	// Pobierz pozycjê kamery
	glm::vec3 cameraPosition = spaceship->cameraPos;

	glm::vec3 spritePosition = glm::vec3(modelMatrix[3]);

	// Oblicz wektor skierowany od sprita do kamery
	glm::vec3 spriteToCamera = glm::normalize(cameraPosition - spritePosition);

	// Oblicz k¹t rotacji w stopniach wokó³ osi Y
	float angle = glm::degrees(atan2(spriteToCamera.x, spriteToCamera.z));

	// Utwórz macierz rotacji wok³ osi Y
	glm::mat4 rotationMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f));
	// Utwórz macierz widoku-projekcji
	glm::mat4 viewProjectionMatrix = Core::createPerspectiveMatrix() * spaceship->createCameraMatrix();

	// Kombinuj macierze transformacji
	glm::mat4 transformation = viewProjectionMatrix * modelMatrix * rotationMatrix;

	// Przeka¿ macierze do shadera
	glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, glm::value_ptr(transformation));
	glUniformMatrix4fv(glGetUniformLocation(program, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
	glUniform3fv(glGetUniformLocation(program, "activeColor"), 1, glm::value_ptr(color));
	glUniform1f(glGetUniformLocation(program, "progress"), progress);

	glBindVertexArray(this->VAO);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	glBindVertexArray(0);
};
void Core::SpriteRenderer::DrawSprite(GLuint spriteTexture, const glm::mat4 modelMatrix, GLuint program) {

	Spaceship* spaceship = Spaceship::getInstance();

	// Pobierz pozycjê kamery
	glm::vec3 cameraPosition = spaceship->cameraPos;

	glm::vec3 spritePosition = glm::vec3(modelMatrix[3]);

	// Oblicz wektor skierowany od sprita do kamery
	glm::vec3 spriteToCamera = glm::normalize(cameraPosition - spritePosition);

	// Oblicz k¹t rotacji w stopniach wokó³ osi Y
	float angle = glm::degrees(atan2(spriteToCamera.x, spriteToCamera.z));
	
	// Utwórz macierz rotacji wok³ osi Y
	glm::mat4 rotationMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f));
	// Utwórz macierz widoku-projekcji
	glm::mat4 viewProjectionMatrix = Core::createPerspectiveMatrix() * spaceship->createCameraMatrix();

	// Kombinuj macierze transformacji
	glm::mat4 transformation = viewProjectionMatrix * modelMatrix * rotationMatrix;

	// Przeka¿ macierze do shadera
	glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, glm::value_ptr(transformation));
	glUniformMatrix4fv(glGetUniformLocation(program, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
	Core::SetActiveTexture(spriteTexture, "colorTexture", program, 0);

	glBindVertexArray(this->VAO);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
	glBindVertexArray(0);
}

void Core::SpriteRenderer::initRenderData()
{
	// Definicja wierzcho³ków kwadratu
	float vertices[] = {
		// Postions						//colors		// texture coordiantes
		-0.5f, -0.5f, 0.0f,		1.0f, 0.0f, 0.0f,	0.0f, 0.0f, // Left down
		-0.5f, 0.5f, 0.0f,		0.0f, 1.0f, 0.0f,	0.0f,1.0f, // Left up
		 0.5f, 0.5f, 0.0f,		0.0f, 0.0f, 1.0f,	1.0f, 1.0f,// Right up
		 0.5f, -0.5f, 0.0f,		1.0f, 1.0f, 1.0f,   1.0f,0.0f// Right down
	};

	// Definicja indeksów wierzcho³ków dla kwadratu
	unsigned int indices[] = {
		0, 2, 1, // Upper triangle
		0, 3, 2  // Lower triangle
	};
	
	glGenVertexArrays(1, &this->VAO);
	glGenBuffers(1, &this->VBO);
	glGenBuffers(1, &this->EBO);

	glBindVertexArray(this->VAO);

	// Wype³nij bufor wierzcho³ków
	glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// Wype³nij bufor indeksów
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);

	glEnableVertexAttribArray(1);
	// Konfiguracja atrybutu koordynatow kolorow
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));

	glEnableVertexAttribArray(2);
	// Konfiguracja atrybutu koordynatow tekstury
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));

	glBindVertexArray(0);
}