#include "Graphics.h"
// This class is a tidy way to keep all access to graphic systems in one place, generally we will do things like create textures, framebuffers, and control
// the set up and display of our graphic classes and content. Keeping it away directly from the main app

#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace glm;


Graphics::Graphics()
{
	// don't really want to do anything here but could move init here
}
Graphics::~Graphics()
{

}


///
// Create a simple width x height texture image with RGBA format
//
GLuint Graphics::CreateSimpleTexture2D(int width, int height, char* TheData)
{
	// Texture object handle
	GLuint textureId;

	// Use tightly packed data
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	// Generate a texture object
	glGenTextures(1, &textureId);

	// Bind the texture object
	glBindTexture(GL_TEXTURE_2D, textureId);

	// Load the texture

	glTexImage2D(GL_TEXTURE_2D,
		0,
		GL_RGBA,
		width,
		height,
		0,
		GL_RGBA,
		GL_UNSIGNED_BYTE,
		TheData);

	if (glGetError() != GL_NO_ERROR)
	{
		printf("Oh bugger");
		textureId = -1; //indicate a failed set up
		return textureId;

	}
	// Set the filtering mode
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


	return textureId;
}

/*
 It is far easier to load a shader file, which is easier to edit and save
 that it is to embed it in your code as a char array.
 Now we have be able to create a shader object, pass the shader source
 and them compile the shader.
*/
GLuint Graphics::LoadShader(GLenum type, const char* shaderSrc)
{
	// 1st create the shader object
	GLuint TheShader = glCreateShader(type);

	if (TheShader == 0) return FALSE; // can't allocate so stop.

	// pass the shader source then compile it
	glShaderSource(TheShader, 1, &shaderSrc, NULL);
	glCompileShader(TheShader);

	GLint  IsItCompiled;

	// After the compile we need to check the status and report any errors
	glGetShaderiv(TheShader, GL_COMPILE_STATUS, &IsItCompiled);
	if (!IsItCompiled)
	{
		GLint RetinfoLen = 0;
		glGetShaderiv(TheShader, GL_INFO_LOG_LENGTH, &RetinfoLen);
		if (RetinfoLen > 1)
		{
			// standard output for errors
			char* infoLog = (char*)malloc(sizeof(char) * RetinfoLen);
			glGetShaderInfoLog(TheShader, RetinfoLen, NULL, infoLog);
			fprintf(stderr, "Error compiling this shader:\n%s\n", infoLog);
			free(infoLog);
		}
		glDeleteShader(TheShader);
		return FALSE;
	}
	return TheShader;
}

// This makes a Program object for us, it will report errors in creation but won't freeze the project, so check the error outputs
// returns FALSE (0) if it failed.
GLuint Graphics::MakePO(const char* VertexSrc, const char* FragmentSrc)
{
	// Load and compile the vertex/fragment shaders
	VertexShader = LoadShader(GL_VERTEX_SHADER, (char*)VertexSrc);
	FragmentShader = LoadShader(GL_FRAGMENT_SHADER, (char*)FragmentSrc);

	// Create the program object	
	ProgramObject = glCreateProgram();
	if (ProgramObject == 0)
	{
		printf("Oh bugger, Unusually, PO Generation failed!!\n");
	}
		return FALSE;

	// now we have teh V and F shaders  attach them to the progam object
	glAttachShader(ProgramObject, VertexShader);
	glAttachShader(ProgramObject, FragmentShader);

	// Link the program
	glLinkProgram(ProgramObject);
	// Check the link status
	GLint AreTheylinked;
	glGetProgramiv(ProgramObject, GL_LINK_STATUS, &AreTheylinked);
	if (!AreTheylinked)
	{
		GLint RetinfoLen = 0;
		// check and report any errors
		glGetProgramiv(ProgramObject, GL_INFO_LOG_LENGTH, &RetinfoLen);
		if (RetinfoLen > 1)
		{
			GLchar* infoLog = (GLchar*)malloc(sizeof(char) * RetinfoLen);
			glGetProgramInfoLog(ProgramObject, RetinfoLen, NULL, infoLog);
			fprintf(stderr, "Error linking program:\n%s\n", infoLog);
			free(infoLog);
		}
		glDeleteProgram(ProgramObject);
		return FALSE; 
	}

	

	return ProgramObject;

}