uniform	vec2	u_ds_modifiers;		// x = diffuse, y = specular

float Diffuse_OrenNayar (in float roughness2, in float NL, in vec3 normal, in vec3 viewVec, in vec3 lightVec)
{	// The "simple" version of Oren-Nayar (http://ruh.li/GraphicsOrenNayar.html)
	float NV = dot(normal, viewVec);
	float angleVN = acos(NV);
	float angleLN = acos(NL);
	float alpha = max(angleVN, angleLN);
	float beta = min(angleVN, angleLN);
	float gamma = dot(viewVec - normal * NV, lightVec - normal * NL);
	float A = 1.0 - 0.5 * (roughness2 / (roughness2 + 0.57));
	float B = 0.45 * (roughness2 / (roughness2 + 0.09));
	float C = sin(alpha) * tan(beta);
	return max(0.0, NL) * (A + B * max(0.0, gamma) * C);
}

void DoPBR (in vec3 light, in vec4 specular, in vec3 N, in vec3 L, in vec3 V, in float NL, in float pbr)
{
	vec3 outColor;
	vec3 color = texture(u_ColorBuffer, gl_FragCoord.xy).rgb;

	if (abs(pbr) == 0.5)
	{
		outColor = light * color * u_ds_modifiers.x;
		if (u_noSpecular == 0.0)
		{
			vec3 H = normalize(L + V);
			float pwr = pow(dot(N, H), specular.a * 256.0);
			if (isnan(pwr))
				pwr = 0.0;
			outColor += light * pwr * specular.rgb * u_ds_modifiers.y;
		}
		fragData = max(outColor, vec3(0.0));
		return;
	}

	// Physically Based Rendering:
	// specular.r = metallic
	// specular.g = emission
	// specular.b = roughness
	// specular.a = ambient occlusion

	float roughness = max(specular.b, 0.1);
	float roughness2 = roughness * roughness;
	outColor = light * Diffuse_OrenNayar(roughness2, NL, N, V, L) * color * u_ds_modifiers.x;

	if (u_noSpecular == 0.0)
	{
		vec3 H = normalize(L + V);

		float LH = max(dot(L, H), 0.0);
		float NH = max(dot(N, H), 0.0);
		float NV = max(dot(N, V), 0.0);

		float roughness4 = roughness2 * roughness2;
		float denom = NH * NH * (roughness4 - 1.0) + 1.0;
		float D = roughness4 / (denom * denom);

		float F_b = exp2((-5.55473 * LH - 6.98316 ) * LH);	// gaussian power approximation		was: float F_b = pow(1.0 - LH, 5.0);
		vec3 F0 = mix(vec3(0.04), color, specular.r);	// fresnel is constant here: 0.04
		vec3 F = mix(vec3(F_b), vec3(1.0), F0);

		float k = (roughness2 + 2.0 * roughness + 1.0) * (1.0 / 8.0);
		float G = 1.0 / (mix(NL, 1.0, k) * mix(NV, 1.0, k));

		outColor += light * D * G * F * 0.25 * u_ds_modifiers.y;
	}

	fragData = max(outColor, vec3(0.0));
}
