#include "Water.h"

const char* CWater::vp = "\
	varying vec3 view_vec;\
	varying vec3 normal;\
	varying vec4 vert_pos;\
	void main(void)\
	{\
	vert_pos		= gl_Vertex;\
	gl_Position		= ftransform();\
	gl_ClipVertex	= gl_Position;\
	view_vec		= gl_ModelViewMatrixInverseTranspose[3].xyz-vec3(gl_ModelViewMatrix*gl_Vertex);\
	normal			= gl_NormalMatrix * gl_Normal;\
	gl_TexCoord[0]	= gl_MultiTexCoord0;\
	}\
	";

const char* CWater::fp = "\
	uniform sampler2D tex0;\
	uniform sampler2D tex1;\
	uniform sampler2D tex2;\
	uniform float pos;\
	varying vec3 view_vec;\
	varying vec3 normal;\
	varying vec4 vert_pos;\
	void main(void)\
	{\
	vec3 view		= normalize( view_vec );\
	vec4 tuv		= gl_TextureMatrix[0] * vert_pos;\
	vec4 tuv_refl	= gl_TextureMatrix[2] * vert_pos;\
	vec4 tex_noiz	= texture2D( tex1, gl_TexCoord[0].xy*vec2(2.3,2.4)+pos*1.1 );\
	vec4 tex_noiz2	= texture2D( tex1, gl_TexCoord[0].xy*vec2(1.1,1.4)-pos*1.35 );\
	tex_noiz		= ( tex_noiz * 0.6 + tex_noiz2 * 0.4 ) * 2.0 - 1.0;\
	tuv.xyz			+= tex_noiz.xyz * 0.14;\
	tuv_refl.xyz	+= tex_noiz.xyz * 0.02 + vec3( 0.0, 0.001, 0.0 );\
	float facing	= 1.0 - dot(view, normalize(normal+vec3(tex_noiz.x, tex_noiz.z, tex_noiz.y)));\
	float fresnel	= pow(facing, 4.0);\
	vec4 water_col	= texture2DProj(tex0, tuv);\
	vec4 refl_col	= texture2DProj(tex2, tuv_refl );\
	gl_FragColor	= mix( water_col, vec4(0.0,0.08,0.1,1.0), facing)*0.8 + refl_col * fresnel*1.0;\
	}\
	";

const float CWater::BiasMatrix[] = {
	0.5f, 0.0f, 0.0f, 0.0f,
	0.0f, 0.5f, 0.0f, 0.0f,
	0.0f, 0.0f, 0.5f, 0.0f,
	0.5f, 0.5f, 0.5f, 1.0f
};

bool	CWater::Generate(){
	return Shader.Compile( vp, fp );
}

void	CWater::Render( CMap& Refl, CMap& Refr, CMap& Norm ){
	float Size = 8.0f;
	float UVTiling = 10.0f;
	Shader.Bind( DeltaTime );
	glColor3f( 0,0,0.5f );

	// setup normalmap texture unit
	glActiveTextureARB( GL_TEXTURE1 );
	Norm.Bind();

	// setup reflection texture unit
	glActiveTextureARB( GL_TEXTURE2 );
	Refl.Bind();
	glMatrixMode( GL_TEXTURE );
	glLoadIdentity ();
	glMultMatrixf  ( BiasMatrix );
	glMultMatrixf  ( MtxProjectionReflect );
	glMultMatrixf  ( MtxModelReflect );
	glMatrixMode( GL_MODELVIEW );

	// setup refraction texture unit
	glActiveTextureARB( GL_TEXTURE0 );
	Refr.Bind();
	glMatrixMode( GL_TEXTURE );
	glLoadIdentity ();
	glMultMatrixf  ( BiasMatrix );
	glMultMatrixf  ( MtxProjectionRefract );
	glMultMatrixf  ( MtxModelRefract );
	glMatrixMode( GL_MODELVIEW );
	
	glNormal3f( 0,1,0 );
	glBegin( GL_QUADS );
	glMultiTexCoord2fARB( GL_TEXTURE0, 0,0 );				glVertex3f( -Size, 0, -Size );
	glMultiTexCoord2fARB( GL_TEXTURE0, UVTiling,0 );		glVertex3f(  Size, 0, -Size );
	glMultiTexCoord2fARB( GL_TEXTURE0, UVTiling,UVTiling );	glVertex3f(  Size, 0,  Size );
	glMultiTexCoord2fARB( GL_TEXTURE0, 0,UVTiling );		glVertex3f( -Size, 0,  Size );
	glEnd();
	glActiveTextureARB( GL_TEXTURE0 );
	glMatrixMode( GL_TEXTURE );
	glLoadIdentity ();
	glMatrixMode( GL_MODELVIEW );
	Shader.Unbind();
}

void	CWater::SetDelta( float dt ){
	DeltaTime = dt;
}
