#include "skybox.h"

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

bool CSkybox::Init()
{
	// load textures and shaders first and return false if an error occurs

	bool Error = false;

	char *FileNames[] = {"jajlands1_ft.jpg", "jajlands1_bk.jpg", "jajlands1_dn.jpg", "jajlands1_up.jpg", "jajlands1_rt.jpg", "jajlands1_lf.jpg"};

	Error |= !Texture.LoadTextureCubeMap(FileNames);

	Error |= !SkyBox.Load("skybox.vert", "skybox.frag");
	
	if(Error)
	{
		return false;
	}

	// get uniform locations

	SkyBox.UniformLocations = new GLuint[2];
	SkyBox.UniformLocations[0] = glGetUniformLocation(SkyBox, "CameraPosition");
	SkyBox.UniformLocations[1] = glGetUniformLocation(SkyBox, "ViewProjectionMatrix");

	// get attribute locations

	SkyBox.AttribLocations = new GLuint[1];
	SkyBox.AttribLocations[0] = glGetAttribLocation(SkyBox, "vert_Position");

	// init data

	vec3 *SkyBoxVertices = new vec3[36];

	int v = 0;

	// +x = right
	SkyBoxVertices[v++] = vec3( 1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f,  1.0f);
	SkyBoxVertices[v++] = vec3( 1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f, -1.0f);
	// -x = left
	SkyBoxVertices[v++] = vec3(-1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f, -1.0f);
	SkyBoxVertices[v++] = vec3(-1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f,  1.0f);
	// +y = top
	SkyBoxVertices[v++] = vec3(-1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f,  1.0f);
	SkyBoxVertices[v++] = vec3( 1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f, -1.0f);
	// -y = bottom
	SkyBoxVertices[v++] = vec3(-1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f, -1.0f);
	SkyBoxVertices[v++] = vec3( 1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f,  1.0f);
	// +z = back
	SkyBoxVertices[v++] = vec3( 1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f,  1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f,  1.0f);
	SkyBoxVertices[v++] = vec3(-1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f,  1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f,  1.0f);
	// -z = front
	SkyBoxVertices[v++] = vec3(-1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f, -1.0f, -1.0f); SkyBoxVertices[v++] = vec3( 1.0f,  1.0f, -1.0f);
	SkyBoxVertices[v++] = vec3( 1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f,  1.0f, -1.0f); SkyBoxVertices[v++] = vec3(-1.0f, -1.0f, -1.0f);

	// init VBO

	glGenBuffers(1, &VBO);
	
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, 36 * 3 * 4, SkyBoxVertices, GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, 0); // don't forget to unbind current VBO

	// free allocated memory

	delete [] SkyBoxVertices;

	// init VAO

	glGenVertexArrays(1, &VAO);

	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glVertexAttribPointer(SkyBox.AttribLocations[0], 3, GL_FLOAT, GL_FALSE, 3 * 4, (void*)0);
	glEnableVertexAttribArray(SkyBox.AttribLocations[0]);

	glBindVertexArray(0); // don't forget to unbind current VAO

	return true;
}

void CSkybox::Render(mat4x4 &ViewProjectionMatrix, vec3 &CameraPosition)
{
	glUseProgram(SkyBox);
	glUniform3fv(SkyBox.UniformLocations[0], 1, (float*)&CameraPosition);
	glUniformMatrix4fv(SkyBox.UniformLocations[1], 1, GL_FALSE, (float*)&ViewProjectionMatrix);
	glBindTexture(GL_TEXTURE_CUBE_MAP, Texture);
	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 36);
	glBindVertexArray(0); // don't forget to unbind current VAO
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0); // don't forget to unbind current texture
	glUseProgram(0); // don't forget to unbind current program
}

void CSkybox::Destroy()
{
	Texture.Destroy();
	SkyBox.Destroy();
	glDeleteBuffers(1, &VBO);
	glDeleteVertexArrays(1, &VAO);
}
