#include "EdgeBuffer.h"
#include "ShaderManager.h"
#include "MatrixManager.h"
#include "DrawFunc.h"

EdgeBuffer::EdgeBuffer(int nWidth, int nHeight)
{
	this->m_nWidth=nWidth;
	this->m_nHeight=nHeight;

	glEnable(GL_TEXTURE_2D);

	glGenFramebuffers(1,&m_nFrameBuffer);
	glBindFramebuffer(GL_FRAMEBUFFER, m_nFrameBuffer);
	
	glGenTextures(1, &m_nEdgeTex);
	glBindTexture(GL_TEXTURE_2D, m_nEdgeTex);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_nWidth, m_nHeight, 0, GL_RGBA, GL_FLOAT, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_nEdgeTex, 0);

	// check FbO status
	GLenum FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if(FBOstatus != GL_FRAMEBUFFER_COMPLETE)
	{
		glBindFramebuffer(GL_FRAMEBUFFER, 0); // error
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

EdgeBuffer::~EdgeBuffer()
{
	glDeleteFramebuffers(1,&m_nFrameBuffer);
}


void EdgeBuffer::drawToBuffer(GLuint normalTex, GLuint depthTex, View *view)
{
	GLSLProgram *glslProgram = ShaderManager::getInstance()->getShader("Edge");
	glslProgram->use();

	bind();
	GLenum mrt[] = {GL_COLOR_ATTACHMENT0_EXT};
	glDrawBuffers(1, mrt);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushAttrib( GL_VIEWPORT_BIT );
	glViewport( 0, 0, getWidth(), getHeight());

	MatrixManager::getInstance()->putMatrix4(PROJECTION, glm::mat4(1.0f));
	view->use3D(false);

	glBindAttribLocation(glslProgram->getHandle(), 0, "v_vertex");
	glBindAttribLocation(glslProgram->getHandle(), 1, "v_texture");

	glslProgram->sendUniform("projectionMatrix", &MatrixManager::getInstance()->getMatrix4(PROJECTION)[0][0]);
	glslProgram->sendUniform("near", (float)view->getNear());
	glslProgram->sendUniform("far", (float)view->getFar());

	glActiveTexture(GL_TEXTURE0); 
	glBindTexture(GL_TEXTURE_2D, normalTex);
	glActiveTexture(GL_TEXTURE1); 
	glBindTexture(GL_TEXTURE_2D, depthTex);
	glslProgram->sendUniform("normalTex",0);
	glslProgram->sendUniform("depthTex",1);

	drawScreenShader(0,0,1.0f,1.0f);

	glslProgram->disable();
	unbind();
	glPopAttrib();
}

void EdgeBuffer::bind() 
{
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_nFrameBuffer);
}

void EdgeBuffer::unbind() 
{
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void EdgeBuffer::bindEdgeTex() 
{
	glBindTexture(GL_TEXTURE_2D, m_nEdgeTex);
}

GLuint EdgeBuffer::getEdgeTex() 
{
	return m_nEdgeTex;
}

int EdgeBuffer::getWidth() 
{
	return m_nWidth;
}

int EdgeBuffer::getHeight() 
{
	return m_nHeight;
}