#import bevy_pbr::{
    pbr_fragment::pbr_input_from_standard_material,
    pbr_functions::{alpha_discard, calculate_tbn_mikktspace},
}

#ifdef PREPASS_PIPELINE
#import bevy_pbr::{
    prepass_io::{VertexOutput, FragmentOutput},
    pbr_deferred_functions::deferred_output,
}
#else
#import bevy_pbr::{
    forward_io::{VertexOutput, FragmentOutput},
    pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing},
}
#endif

const BLACKSITE_SURFACE_ABI_VERSION: u32 = 1u;
const BLACKSITE_SURFACE_UNLIT: u32 = 1u;
const STANDARD_MATERIAL_FLAGS_UNLIT_BIT: u32 = 1u << 5u;

struct SurfaceUniform {
    shader_id: u32,
    flags: u32,
    alpha_cutoff: f32,
    abi_version: u32,
    params: array<vec4<f32>, 16>,
    uv_transforms: array<vec4<f32>, 8>,
}

@group(#{MATERIAL_BIND_GROUP}) @binding(100) var<uniform> surface_uniform: SurfaceUniform;
@group(#{MATERIAL_BIND_GROUP}) @binding(101) var surface_texture0: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(102) var surface_sampler0: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(103) var surface_texture1: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(104) var surface_sampler1: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(105) var surface_texture2: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(106) var surface_sampler2: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(107) var surface_texture3: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(108) var surface_sampler3: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(109) var surface_texture4: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(110) var surface_sampler4: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(111) var surface_texture5: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(112) var surface_sampler5: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(113) var surface_texture6: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(114) var surface_sampler6: sampler;
@group(#{MATERIAL_BIND_GROUP}) @binding(115) var surface_texture7: texture_2d<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(116) var surface_sampler7: sampler;

struct SurfaceInput {
    uv0: vec2<f32>,
    world_position: vec3<f32>,
    world_normal: vec3<f32>,
}

struct SurfaceParams {
    lanes: array<vec4<f32>, 16>,
}

struct SurfaceSamples {
    values: array<vec4<f32>, 8>,
}

struct Surface {
    base_color: vec4<f32>,
    normal_ts: vec3<f32>,
    emissive: vec3<f32>,
    metallic: f32,
    perceptual_roughness: f32,
    reflectance: f32,
    occlusion: f32,
    model: u32,
}

fn surface_default() -> Surface {
    var surface: Surface;
    surface.base_color = vec4<f32>(1.0);
    surface.normal_ts = vec3<f32>(0.0, 0.0, 1.0);
    surface.emissive = vec3<f32>(0.0);
    surface.metallic = 0.0;
    surface.perceptual_roughness = 0.5;
    surface.reflectance = 0.5;
    surface.occlusion = 1.0;
    surface.model = 0u;
    return surface;
}

fn surface_uv(index: u32, uv: vec2<f32>) -> vec2<f32> {
    let transform = surface_uniform.uv_transforms[index];
    return uv * transform.xy + transform.zw;
}

fn surface_samples(uv: vec2<f32>) -> SurfaceSamples {
    var samples: SurfaceSamples;
    samples.values[0] = textureSample(surface_texture0, surface_sampler0, surface_uv(0u, uv));
    samples.values[1] = textureSample(surface_texture1, surface_sampler1, surface_uv(1u, uv));
    samples.values[2] = textureSample(surface_texture2, surface_sampler2, surface_uv(2u, uv));
    samples.values[3] = textureSample(surface_texture3, surface_sampler3, surface_uv(3u, uv));
    samples.values[4] = textureSample(surface_texture4, surface_sampler4, surface_uv(4u, uv));
    samples.values[5] = textureSample(surface_texture5, surface_sampler5, surface_uv(5u, uv));
    samples.values[6] = textureSample(surface_texture6, surface_sampler6, surface_uv(6u, uv));
    samples.values[7] = textureSample(surface_texture7, surface_sampler7, surface_uv(7u, uv));
    return samples;
}
