#include "client/render/shader/EntityShader.h"

namespace blitz {
namespace shader {

#ifdef __ANDROID__
static const char vertexSource[] =
	R"(#version 300 es

precision mediump float;

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 textureCoords;
layout(location = 2) in vec3 normal;

uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;

out vec3 toLightVector;
out vec3 surfaceNormal;

void main(void){
	vec3 lightPosition = vec3(0, 15, 0);

	vec4 worldPos = modelMatrix * vec4(position, 1.0);

	toLightVector = lightPosition - worldPos.xyz;
	surfaceNormal = vec4(modelMatrix * vec4(normal, 0.0)).xyz;

	gl_Position = projectionMatrix * viewMatrix * worldPos;
}
)";

static const char fragmentSource[] =
	R"(#version 300 es

precision mediump float;

in vec3 toLightVector;
in vec3 surfaceNormal;

out vec4 out_color;

void main(void){

    vec3 unitNormal = normalize(surfaceNormal);
	vec3 unitLightVector = normalize(toLightVector);

	float diffuse = max(0.2, dot(unitNormal, unitLightVector));

	float brightness = diffuse;

	out_color = vec4(1.0, 1.0, 1.0, 1.0) * brightness;

}
)";
#else
static const char vertexSource[] = R"(
#version 330

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 textureCoords;
layout(location = 2) in vec3 normal;

uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
uniform vec3 lightPosition = vec3(0, 15, 0);

out vec3 toLightVector;
out vec3 surfaceNormal;

void main(void){
	vec4 worldPos = modelMatrix * vec4(position, 1.0);

	toLightVector = lightPosition - worldPos.xyz;
	surfaceNormal = (modelMatrix * vec4(normal, 0.0)).xyz;

	gl_Position = projectionMatrix * viewMatrix * worldPos;
}
)";

static const char fragmentSource[] = R"(
#version 330

in vec3 toLightVector;
in vec3 surfaceNormal;

out vec4 out_color;

void main(void){

	vec3 unitNormal = normalize(surfaceNormal);
	vec3 unitLightVector = normalize(toLightVector);

	float diffuse = max(0.2, dot(unitNormal, unitLightVector));

	float brightness = diffuse;

	out_color = vec4(1.0, 1.0, 1.0, 1.0) * brightness;
}
)";
#endif

EntityShader::EntityShader() : ShaderProgram() {}

void EntityShader::LoadShader() {
	ShaderProgram::LoadProgram(vertexSource, fragmentSource);
}

void EntityShader::GetAllUniformLocation() {
	m_LocationViewMatrix = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
	m_LocationTransform = static_cast<unsigned int>(GetUniformLocation("modelMatrix"));
	m_LocationProjectionMatrix = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
}

void EntityShader::SetProjectionMatrix(const Mat4f& proj) const {
	LoadMat4(m_LocationProjectionMatrix, proj);
}

void EntityShader::SetViewMatrix(const Mat4f& view) const {
	LoadMat4(m_LocationViewMatrix, view);
}

void EntityShader::SetModelTransform(const Mat4f& transform) const {
	LoadMat4(m_LocationTransform, transform);
}

}  // namespace shader
}  // namespace blitz