#include "Water.hpp"


#include "Game.hpp"
#include "Global.hpp"

Water::Water(Game& game):
m_Game(game),
m_WaveTime(0)
{
	//create the textures:
	glGenTextures(1, &m_ReflectionMap);
	glBindTexture(GL_TEXTURE_2D, m_ReflectionMap);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGBA, GL_BYTE, NULL);

	glGenTextures(1, &m_RefractionMap);
	glBindTexture(GL_TEXTURE_2D, m_RefractionMap);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGBA, GL_BYTE, NULL);

	glBindTexture(GL_TEXTURE_2D, 0);

	//a depth buffer:
	glGenRenderbuffers(1, &m_DepthBuffer);
	glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 512, 512);

	//bind the framebuffers
	m_ReflectionBuffer.AttachTexture(GL_TEXTURE_2D, m_ReflectionMap);
	m_ReflectionBuffer.AttachRenderBuffer(m_DepthBuffer, GL_DEPTH_ATTACHMENT);

	m_RefractionBuffer.AttachTexture(GL_TEXTURE_2D, m_RefractionMap);
	m_RefractionBuffer.AttachRenderBuffer(m_DepthBuffer, GL_DEPTH_ATTACHMENT);

	FramebufferObject::Disable();

	//Load the Shader
	m_Shader.Load(ResourceDir+"Water.vert", ResourceDir+"Water.frag");
}


void Water::Render()
{
	m_Shader.Set();
	m_Shader.SetUniform("ReflectionTex", 0);
	m_Shader.SetUniform("RefractionTex", 1);
	try
	{
		m_Shader.SetUniform("u_WaveTime", m_WaveTime);
	}
	catch(...)
	{}

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, m_ReflectionMap);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, m_RefractionMap);

	glActiveTexture(GL_TEXTURE0);

	glBegin(GL_QUADS);

	const int c=100;
	for(int i=0; i<c; ++i)
	{
		for(int j=0; j<c; ++j)
		{
			float px=-21;
			float py=-21;
			float dx=(22.0f-px)/c;
			float dy=(29.0f-py)/c;

			glVertex3f(px	+(i  )*dx, py	+(j  )*dy, 0);
			glVertex3f(px	+(i+1)*dx, py	+(j  )*dy, 0);
			glVertex3f(px	+(i+1)*dx, py	+(j+1)*dy, 0);
			glVertex3f(px	+(i  )*dx, py	+(j+1)*dy, 0);


			/*glVertex3f(-10, 0,  0);
			glVertex3f( 10, 0,  0);
			glVertex3f( 10, 12, 0);
			glVertex3f(-10, 12, 0);*/
		}
	}

	glEnd();

	m_Shader.Unset();
}


void Water::RenderTexture()
{
	double ClipPlaneLe[]={0, 0, 1, 0};
	double ClipPlaneRa[]={0, 0, -1, 0};
	glMatrixMode(GL_MODELVIEW);

	glEnable(GL_CLIP_PLANE0);

	//------ render the reflection: -----
	m_ReflectionBuffer.Bind();
	glEnable(GL_NORMALIZE);
	glPushMatrix();
	glScalef(1.0, 1.0, -1.0);
	glPushAttrib(GL_VIEWPORT_BIT);
	glViewport(0,0, 512, 512);

	glClipPlane(GL_CLIP_PLANE0, ClipPlaneLe);
	glCullFace(GL_FRONT);	

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	m_Game.RenderEntities();

	glCullFace(GL_BACK);

	glPopAttrib();
	glPopMatrix();

	//------ render the refraction: ---------
	m_RefractionBuffer.Bind();
	glEnable(GL_NORMALIZE);
	glPushMatrix();
	glPushAttrib(GL_VIEWPORT_BIT);
	glViewport(0,0, 512, 512);

	glClipPlane(GL_CLIP_PLANE0, ClipPlaneRa);
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	m_Game.RenderEntities();
	
	glPopAttrib();
	glPopMatrix();

	glDisable(GL_CLIP_PLANE0);


	//finished :)
	FramebufferObject::Disable();
}

void Water::onTick(float time)
{
	m_WaveTime+=time;
	if(m_WaveTime>3.14159f*2000.0f)
		m_WaveTime-=3.14159f*2000.0f;
}