@group(0) @binding(0)
var<uniform> viewProjectionMatrix : mat4x4<f32>;

@group(0) @binding(1)
var<storage, read> instancePositions : array<vec4<f32>>;

@group(0) @binding(2)
var<uniform> cameraPosition : vec3<f32>;

@group(0) @binding(3)
var myTexture : texture_2d<f32>;

@group(0) @binding(4)
var mySampler : sampler;

struct VertexOutput {
	@builtin(position) position : vec4<f32>,
	@location(0) worldPosition : vec3<f32>,
	@location(1) worldNormal   : vec3<f32>,
	@location(2) uv            : vec2<f32>,
};

@vertex
fn vertexEntryPoint(
	@location(0) position : vec3<f32>,
	@location(1) normal   : vec3<f32>,
	@location(2) uv       : vec2<f32>,
	@builtin(instance_index) instanceIndex : u32
) -> VertexOutput {
	var output : VertexOutput;

	let instanceOffset = instancePositions[instanceIndex].xyz;
	let worldPosition = position + instanceOffset;

	output.worldPosition = worldPosition;
	output.worldNormal   = normalize(normal);
	output.position      = viewProjectionMatrix * vec4<f32>(worldPosition, 1.0);
	output.uv            = uv;

	return output;
}
@fragment
fn fragmentEntryPoint(
	@location(0) worldPosition : vec3<f32>,
	@location(1) worldNormal   : vec3<f32>,
	@location(2) uv            : vec2<f32>
) -> @location(0) vec4<f32> {

	// For test: encode UV as color (no texture sampling)
	//let baseColor = vec3<f32>(uv, 0.0);

	let baseColor = textureSample(myTexture, mySampler, uv).rgb;

	let pi      = 3.14159265;
	let invPi   = 0.318309886;
	let N       = normalize(worldNormal);
	let V       = normalize(cameraPosition - worldPosition);
	let L       = normalize(vec3<f32>(0.5, 1.0, 0.3));
	let H       = normalize(V + L);

	let metallic  = 0.2;
	let roughness = 0.4;
	let rough2    = roughness * roughness;
	let lightColor = vec3<f32>(1.0);

	let NdotV = max(dot(N, V), 0.001);
	let NdotL = max(dot(N, L), 0.001);
	let NdotH = max(dot(N, H), 0.001);
	let HdotV = max(dot(H, V), 0.001);

	let F0 = mix(vec3<f32>(0.04), baseColor, metallic);
	let f = pow(1.0 - HdotV, 5.0);
	let F = F0 + (1.0 - F0) * f;

	let a2     = rough2 * rough2;
	let NdotH2 = NdotH * NdotH;
	let denom  = NdotH2 * (a2 - 1.0) + 1.0;
	let NDF    = a2 / (pi * denom * denom);

	let k   = (roughness + 1.0);
	let k2  = (k * k) / 8.0;
	let Gv  = NdotV / (NdotV * (1.0 - k2) + k2);
	let Gl  = NdotL / (NdotL * (1.0 - k2) + k2);
	let G   = Gv * Gl;

	let spec = (NDF * G * F) / (4.0 * NdotV * NdotL + 0.001);
	let kd   = (vec3<f32>(1.0) - F) * (1.0 - metallic);
	let diff = kd * baseColor * invPi;

	let color = (diff + spec) * lightColor * NdotL + vec3<f32>(0.03) * baseColor;

	return vec4<f32>(pow(color, vec3<f32>(1.0 / 2.2)), 1.0);
}