#include "StdAfx.h"
#include "IntegrateShader.h"

#include <LibTest/DebugStream.h>

#include "../../GLUtility/ShaderUtil.h"

// IDEでのソース参照用. コンパイルには使わない.
#if 0
#include "..\ShaderCode\Mesh\integrate_shader.frag"
#include "..\ShaderCode\Mesh\integrate_shader.vert"
#endif


IntegrateShader::IntegrateShader(ShaderContext* context) :
	ShaderInterface(context)
{
}

bool IntegrateShader::Initialize(const std::string& shader_libdir)
{
	std::string vert_filename = shader_libdir + "integrate_shader.vert";
	std::string frag_filename = shader_libdir + "integrate_shader.frag";

	if (!ShaderUtil::InitShaderStd(m_Shader, frag_filename, vert_filename))
		return false;

	m_Shader.BeginShader();

	m_SeparateSpecular = GetLocUniform("separate_specular");
	m_EnableVColor     = GetLocUniform("enable_vcolor");
	m_EnableDoubleside = GetLocUniform("enable_doubleside");
	m_EnableLighting   = GetLocUniform("enable_lighting");
	m_EnableFlatShade  = GetLocUniform("enable_flatshade");

	m_SceneMat         = GetLocUniform("scene_mat");
	m_ColorShadowRatio = GetLocUniform("color_shadow_ratio");
	m_EnableHole       = GetLocUniform("enable_hole");
	m_EnableHoleRev    = GetLocUniform("enable_hole_rev");
	m_HolePos          = GetLocUniform("hole_pos");
	m_HoleRange        = GetLocUniform("hole_range");
	m_ConstBrightness  = GetLocUniform("const_brightness");

	m_TexColor     = GetLocUniform("tex_color");
	m_EnabeTexture = GetLocUniform("enable_texture");

	m_TexMatcap    = GetLocUniform("tex_matcap");
	m_EnableMatcap = GetLocUniform("enable_matcap");
	m_MatcapRate   = GetLocUniform("matcap_rate");

	m_TexEnvmap     = GetLocUniform("tex_envmap");
	m_EnableEnvmap  = GetLocUniform("enable_envmap");
	m_EnvReflection = GetLocUniform("env_reflection");
	m_EnvRefract    = GetLocUniform("fresnel_refact");

	m_TangentBuf      = GetLocAttrib("Tangent");
	m_TexNormal       = GetLocUniform("tex_normal");
	m_EnableNormalmap = GetLocUniform("enable_normalmap");

	m_ShadowBuffer     = GetLocUniform("shadow_buffer");
	m_EnableShadow     = GetLocUniform("enable_shadow");
	m_EnableSoftShadow = GetLocUniform("enable_softshadow");
	m_ShadowMat        = GetLocUniform("shadow_mat");

	m_Shader.EndShader();

	return true;
}


void IntegrateShader::BeginShader(void)
{
	m_Shader.BeginShader();

	SceneMain* scene = m_Context->m_Scene;
	Cursor3D& cursor = scene->m_Cursor3d;

	glUniform1i(m_TexMatcap, 3);
	glUniform1i(m_EnableMatcap, false);

	glActiveTexture(GL_TEXTURE2);
	scene->m_EnvImg.BindTexture();
	glUniform1i(m_TexEnvmap, 2);
	glUniform1i(m_EnableEnvmap, scene->m_EnvImg.m_IsEnableReflection);

	SetShadowmap(&m_Context->m_ShadowBuf);

	glActiveTexture(GL_TEXTURE0);
	glUniform1i(m_TexColor, 0);

	lm::matrix4f mat;
	scene->m_WorldTransform.GetRotateMatrix(mat);
	glUniformMatrix4fv(m_SceneMat, 1, GL_FALSE, &mat[0]);

	glUniform1f(m_EnvReflection, scene->m_EnvImg.m_EnvReflection);
	glUniform1f(m_EnvRefract, scene->m_EnvImg.m_EnvRefract);

	glUniform1f(m_ColorShadowRatio, scene->m_ShadowConfig.m_ShadowDarkness);

	glUniform1i(m_EnableHole, cursor.IsHoleActive());
	glUniform1i(m_EnableHoleRev, cursor.IsHoleRevActive());
	if (cursor.IsCircleClipActive())
	{
		float hole_range = scene->GetCursorSphereClipLen();
		lm::vec3f cp = cursor.CursorPos;
		glUniform3f(m_HolePos, cp.x, cp.y, cp.z);
		glUniform1f(m_HoleRange, hole_range);
	}

	glUniform1f(m_ConstBrightness, scene->m_ConstantColorStrength);
}

void IntegrateShader::EndShader(void)
{
	m_Shader.EndShader();
}

GLint IntegrateShader::GetLocUniform(const GLchar* name)
{
	return m_Shader.GetUniformLocation(name);
}

GLint IntegrateShader::GetLocAttrib(const GLchar* name)
{
	return m_Shader.GetAttribLocation(name);
}

void IntegrateShader::SetTangent(const lm::vec3f& v)
{
	glVertexAttrib3fv(m_TangentBuf, v.v());
}

void IntegrateShader::SetColorTextureEnabled(bool enabled)
{
	glUniform1i( m_EnabeTexture , enabled ? 1 : 0 );
}

void IntegrateShader::SetTextureSpecularSeparate(bool enabled)
{
	glUniform1i( m_SeparateSpecular , enabled ? 1 : 0 );
}

void IntegrateShader::SetVColorEnabled(bool enabled)
{
	glUniform1i( m_EnableVColor , enabled ? 1 : 0 );
}

void IntegrateShader::SetDublesideEnabled(bool enabled)
{
	glUniform1i( m_EnableDoubleside , enabled ? 1 : 0 );
}

void IntegrateShader::SetLightingEnabled(bool enabled)
{
	glUniform1i( m_EnableLighting , enabled ? 1 : 0 );
}

void IntegrateShader::SetFlatShade(bool enable_flat)
{
	glUniform1i( m_EnableFlatShade , enable_flat ? 1 : 0 );
}


void IntegrateShader::SetNormalTexture(gl::GlTexture* tex_n)
{
	if (tex_n == NULL)
	{
		glUniform1i(m_EnableNormalmap, false);
		return;
	}

	if (tex_n->HasTextureObject())
	{
		glActiveTexture(GL_TEXTURE4);
		tex_n->BindGL();

		glUniform1i(m_TexNormal, 4);

		glActiveTexture(GL_TEXTURE0);
	}

	glUniform1i(m_EnableNormalmap, tex_n->HasTextureObject());
}

void IntegrateShader::SetMatcap(gl::MatcapImage* matcap)
{
	if (matcap == NULL)
	{
		glUniform1i(m_EnableMatcap, false);
		return;
	}

	if (matcap->HasImage())
	{
		glActiveTexture(GL_TEXTURE3);
		matcap->BindTexture();

		glUniform1i(m_TexMatcap, 3);

		glActiveTexture(GL_TEXTURE0);
	}

	glUniform1f(m_MatcapRate, matcap->m_BlendRate);
	glUniform1i(m_EnableMatcap, matcap->HasImage());
}

void IntegrateShader::SetShadowmap(ShadowBuffer* shadow)
{
	SceneMain* scene = m_Context->m_Scene;
	glActiveTexture(GL_TEXTURE1);
	shadow->m_ShadowBuffer.Bind();
	glUniform1i(m_ShadowBuffer, 1);
	glUniform1i(m_EnableShadow, scene->m_ShadowConfig.m_EnableShadow);
	glUniform1i(m_EnableSoftShadow, scene->m_ShadowConfig.m_EnableSoftShadow);
	glUniformMatrix4fv(m_ShadowMat, 1, GL_FALSE, shadow->m_ShadowMatrix.v());
}

GLint IntegrateShader::GetTangentAttribIndex(void)
{
	return m_TangentBuf;
}
