#include "common_header.h"
#include "shaders.h"

CShader::CShader()
{
	Shader = 0;
}

CShader::~CShader()
{
}

CShader::operator GLuint ()
{
	return Shader;
}

bool CShader::Load(char *ShaderFileName, GLenum Type)
{
	FILE *File = fopen(ShaderFileName, "rb");

	if(File == NULL)
	{
		return false;
	}

	fseek(File, 0, SEEK_END);
	long Size = ftell(File);
	fseek(File, 0, SEEK_SET);
	char *Source = new char[Size + 1];
	fread(Source, 1, Size, File);
	fclose(File);
	Source[Size] = 0;

	Shader = glCreateShader(Type);

	glShaderSource(Shader, 1, (const char**)&Source, NULL);
	delete [] Source;
	glCompileShader(Shader);

	int CompileStatus;
	glGetShaderiv(Shader, GL_COMPILE_STATUS, &CompileStatus);

	if(CompileStatus == GL_FALSE)
	{
		int InfoLogLength = 0;
		glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &InfoLogLength);
	
		if(InfoLogLength > 0)
		{
			int HeaderLength = (int)strlen(ShaderFileName) + 2;
			char *InfoLog = new char[InfoLogLength + HeaderLength];
			InfoLog[0] = 0;
			strcat(InfoLog, ShaderFileName);
			strcat(InfoLog, "\r\n");
			int CharsWritten  = 0;
			glGetShaderInfoLog(Shader, InfoLogLength, &CharsWritten, InfoLog + HeaderLength);
			MessageBox(NULL, InfoLog, "Error", MB_OK | MB_ICONERROR);
			delete [] InfoLog;
		}

		return false;
	}

	return true;
}

CShaderProgram::CShaderProgram()
{
	UniformLocations = NULL;
	AttribLocations = NULL;
	Program = 0;
}

CShaderProgram::~CShaderProgram()
{
}

CShaderProgram::operator GLuint ()
{
	return Program;
}

bool CShaderProgram::Load(char *VertexShaderFileName, char *FragmentShaderFileName)
{
	bool Error = false;

	Error |= !VertexShader.Load(VertexShaderFileName, GL_VERTEX_SHADER);
	Error |= !FragmentShader.Load(FragmentShaderFileName, GL_FRAGMENT_SHADER);

	if(Error)
	{
		return false;
	}

	Program = glCreateProgram();
	glAttachShader(Program, VertexShader);
	glAttachShader(Program, FragmentShader);
	glLinkProgram(Program);

	int LinkStatus;
	glGetProgramiv(Program, GL_LINK_STATUS, &LinkStatus);

	if(LinkStatus == GL_FALSE)
	{
		int InfoLogLength = 0;
		glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &InfoLogLength);
	
		if(InfoLogLength > 0)
		{
			int HeaderLength = (int)strlen(VertexShaderFileName) + 2 + (int)strlen(FragmentShaderFileName) + 2;
			char *InfoLog = new char[InfoLogLength + HeaderLength];
			InfoLog[0] = 0;
			strcat(InfoLog, VertexShaderFileName);
			strcat(InfoLog, ", ");
			strcat(InfoLog, FragmentShaderFileName);
			strcat(InfoLog, "\r\n");
			int CharsWritten  = 0;
			glGetProgramInfoLog(Program, InfoLogLength, &CharsWritten, InfoLog + HeaderLength);
			MessageBox(NULL, InfoLog, "Error", MB_OK | MB_ICONERROR);
			delete [] InfoLog;
		}

		return false;
	}

	return true;
}

void CShaderProgram::Destroy()
{
	delete [] UniformLocations;
	delete [] AttribLocations;

	glDetachShader(Program, VertexShader);
	glDetachShader(Program, FragmentShader);
	glDeleteShader(VertexShader);
	glDeleteShader(FragmentShader);
	glDeleteProgram(Program);
}
