in vec2 vertex_uv;
in vec3 vertex_normal;
in vec4 vertex_tangent;
in vec3 vertex_pos;

#include "drive/common/brdf.glsl"


// Geometric specular antialiasing (Valve) — raises roughness using screen-space
// normal derivatives to suppress specular shimmer on dense/curved geometry.
float valveSpecularAA(vec3 geometricNormal, float roughness)
{
	vec3 dnx = dFdx(geometricNormal);
	vec3 dny = dFdy(geometricNormal);
	float roughFactor = pow(clamp(max(dot(dnx, dnx), dot(dny, dny)), 0.0, 1.0), 1.0 / 4.0);
	return max(roughness, roughFactor);
}

void main()
{
	// ---- Base color: baseColorFactor × baseColorTexture ----
	vec4 baseColor = u_base_color_factor;
#ifdef HAS_BASE_COLOR_TEXTURE
	vec4 baseColorSample = texture(t_base_color, vertex_uv);
	baseColor *= baseColorSample;
#endif

	// ---- Metallic / roughness: glTF packs metallic in B, roughness in G ----
	float metallic  = u_metallic_factor;
	float roughness = u_roughness_factor;
#ifdef HAS_METALLIC_ROUGHNESS_TEXTURE
	vec4 mrSample = texture(t_metallic_roughness, vertex_uv);
	metallic  *= mrSample.b;
	roughness *= mrSample.g;
#endif

	// ---- Occlusion: sampled from R, scaled by occlusionStrength ----
	float occlusion = 1.0;
#ifdef HAS_OCCLUSION_TEXTURE
	float occlusionSample = texture(t_occlusion, vertex_uv).r;
	occlusion = 1.0 + u_occlusion_strength * (occlusionSample - 1.0);
#endif

	// ---- Emissive: emissiveFactor × emissiveTexture ----
	vec3 emissive = u_emissive_factor;
#ifdef HAS_EMISSIVE_TEXTURE
	emissive *= texture(t_emissive, vertex_uv).rgb;
#endif

	// ---- Normal: tangent-space map with .xy scaled by normalScale ----
	vec3 n = normalize(vertex_normal);
	vec3 worldNormal = n;
#ifdef HAS_NORMAL_TEXTURE
	vec3 t = normalize(vertex_tangent.xyz);
	vec3 b = vertex_tangent.w * cross(n, t);
	vec3 tangentNormal = texture(t_normal, vertex_uv).xyz * 2.0 - 1.0;
	tangentNormal.xy *= u_normal_scale;
	worldNormal = normalize(tangentNormal.x * t + tangentNormal.y * b + tangentNormal.z * n);
#endif

	// Geometric specular AA on the final roughness.
	roughness = valveSpecularAA(worldNormal, roughness);

	// ---- Surface state + lighting ----
	vec3 camPos = (inverse(u_view) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
	vec3 viewVector = -normalize(vertex_pos - camPos);
	SurfaceState surf = GetSurfaceState(baseColor.rgb, metallic, roughness, worldNormal, viewVector, vec4(vertex_pos, 1.0), occlusion);

	vec3 color = vec3(0.0);

	vec3 lightDirs[2] = vec3[](
		normalize(vec3( 1.0,  0.0,  0.0)),
		normalize(vec3(-1.0, 0.0, 0.0))
	);
	vec3 lightCols[2] = vec3[](
		vec3(1.0,  0.57, 0.37),
		vec3(0.37, 0.57, 1.0)
	);
	float lightStr[2] = float[](5.0, 5.0);

	for (int i = 0; i < 2; i++)
	{
		LightState light = GetLightState(surf, lightDirs[i], lightCols[i], lightStr[i]);
		color += DirectLighting(surf, light);
	}

	color += ImageLighting(t_brdf, t_irradiance, t_radiance, surf) * 3.0;

	// Emissive is an unlit additive term.
	color += emissive;

	out_color0 = vec4(color, baseColor.a);
}
