#version 300 es
precision highp float;
layout(location = 0) out vec4 outNormal;
layout(location = 1) out vec4 outPosition;
layout(location = 2) out vec4 outBaseColor;
layout(location = 3) out vec4 outMaterial;
layout(location = 4) out vec4 outEmission;

in vec2 tc; // texture coordinate of pixel (interpolated)
in vec3 wfn; // fragment normal of pixel in world space (interpolated)
in vec3 vertPos; // fragment vertex position in world space (interpolated)

uniform sampler2D baseColorTexture; // description="albedo for dielectrics or F0 for metals"
uniform sampler2D roughnessTexture; // description="roughness texture"
uniform sampler2D normalTexture; // description="roughness texture"
uniform sampler2D emissionTexture; // description="emission texture"
uniform float metallic; // description="metallic parameter, 0.0 for dielectrics, 1.0 for metals" defaultval ="0.0"
uniform float reflectance; // description="Fresnel reflectance for dielectrics in the range [0.0, 1.0]" defaultval ="0.5"
uniform vec3 cameraPosition; // camera position in world space

// from http://www.thetenthplanet.de/archives/1180
mat3 cotangentFrame(in vec3 N, in vec3 p, in vec2 uv)
{
    // get edge vectors of the pixel triangle
    vec3 dp1 = dFdx( p );
    vec3 dp2 = dFdy( p );
    vec2 duv1 = dFdx( uv );
    vec2 duv2 = dFdy( uv );
 
    // solve the linear system
    vec3 dp2perp = cross( dp2, N );
    vec3 dp1perp = cross( N, dp1 );
    vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
    vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
 
    // construct a scale-invariant frame 
    float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
    return mat3( T * invmax, B * invmax, N );
}

vec3 applyNormalMap(in vec3 normal, in vec3 viewVec, in vec2 texcoord)
{
    vec3 highResNormal = texture(normalTexture, texcoord).xyz;
    highResNormal = normalize(highResNormal * 2.0 - 1.0);
    mat3 TBN = cotangentFrame(normal, -viewVec, texcoord);
    return normalize(TBN * highResNormal);
}

void main() {
  // surface normal 
  vec3 n = normalize(wfn);
  vec3 viewDir = normalize(cameraPosition - vertPos);
  n = applyNormalMap(n, viewDir, tc); // (todo: explain normal maps in the next episode of Shaders Monthly)
  
  // render to target 0
  outNormal.rgb = n;
  outNormal.a = 1.0;
  
  // render to target 1
  outPosition.rgb = vertPos;
  outPosition.a = 1.0;
  
  // render to target 2
  outBaseColor = texture(baseColorTexture, tc);
  
  // render to target 3
  outMaterial.r = metallic;
  outMaterial.g = texture(roughnessTexture, tc).r;
  outMaterial.b = reflectance;
  outMaterial.a = 1.0;
  
  // render to target 4
  outEmission = texture(emissionTexture, tc);
  outEmission.a = 1.0;
}




