; SPIR-V
; Version: 1.2
; Generator: rspirv
; Bound: 294
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %85 "vs_main" %75 %78 %80 %82 %84
OpEntryPoint Fragment %143 "fs_main" %134 %137 %140 %142
OpEntryPoint Fragment %228 "fs_main_without_storage" %221 %223 %225 %227
OpExecutionMode %143 OriginUpperLeft
OpExecutionMode %228 OriginUpperLeft
%3 = OpString "shadow.wgsl"
OpSource Unknown 0 %3 "struct Globals {
    view_proj: mat4x4<f32>,
    num_lights: vec4<u32>,
}

@group(0)
@binding(0)
var<uniform> u_globals: Globals;

struct Entity {
    world: mat4x4<f32>,
    color: vec4<f32>,
}

@group(1)
@binding(0)
var<uniform> u_entity: Entity;

/* Not useful for testing
@vertex
fn vs_bake(@location(0) position: vec4<i32>) -> @builtin(position) vec4<f32> {
    return u_globals.view_proj * u_entity.world * vec4<f32>(position);
}
*/

struct VertexOutput {
    @builtin(position) proj_position: vec4<f32>,
    @location(0) world_normal: vec3<f32>,
    @location(1) world_position: vec4<f32>,
}

@vertex
fn vs_main(
    @location(0) position: vec4<i32>,
    @location(1) normal: vec4<i32>,
) -> VertexOutput {
    let w = u_entity.world;
    let world_pos = u_entity.world * vec4<f32>(position);
    var out: VertexOutput;
    out.world_normal = mat3x3<f32>(w[0].xyz, w[1].xyz, w[2].xyz) * vec3<f32>(normal.xyz);
    out.world_position = world_pos;
    out.proj_position = u_globals.view_proj * world_pos;
    return out;
}

// fragment shader

struct Light {
    proj: mat4x4<f32>,
    pos: vec4<f32>,
    color: vec4<f32>,
}

@group(0)
@binding(1)
var<storage, read> s_lights: array<Light>;
@group(0)
@binding(1)
var<uniform> u_lights: array<Light, 10>; // Used when storage types are not supported
@group(0)
@binding(2)
var t_shadow: texture_depth_2d_array;
@group(0)
@binding(3)
var sampler_shadow: sampler_comparison;

fn fetch_shadow(light_id: u32, homogeneous_coords: vec4<f32>) -> f32 {
    if (homogeneous_coords.w <= 0.0) {
        return 1.0;
    }
    // compensate for the Y-flip difference between the NDC and texture coordinates
    let flip_correction = vec2<f32>(0.5, -0.5);
    // compute texture coordinates for shadow lookup
    let proj_correction = 1.0 / homogeneous_coords.w;
    let light_local = homogeneous_coords.xy * flip_correction * proj_correction + vec2<f32>(0.5, 0.5);
    // do the lookup, using HW PCF and comparison
    return textureSampleCompareLevel(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z * proj_correction);
}

const c_ambient: vec3<f32> = vec3<f32>(0.05, 0.05, 0.05);
const c_max_lights: u32 = 10u;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    let normal = normalize(in.world_normal);
    // accumulate color
    var color: vec3<f32> = c_ambient;
    for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
        let light = s_lights[i];
        // project into the light space
        let shadow = fetch_shadow(i, light.proj * in.world_position);
        // compute Lambertian diffuse term
        let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
        let diffuse = max(0.0, dot(normal, light_dir));
        // add light contribution
        color += shadow * diffuse * light.color.xyz;
    }
    // multiply the light by material color
    return vec4<f32>(color, 1.0) * u_entity.color;
}

// The fragment entrypoint used when storage buffers are not available for the lights
@fragment
fn fs_main_without_storage(in: VertexOutput) -> @location(0) vec4<f32> {
    let normal = normalize(in.world_normal);
    var color: vec3<f32> = c_ambient;
    for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
        // This line is the only difference from the entrypoint above. It uses the lights
        // uniform instead of the lights storage buffer
        let light = u_lights[i];
        let shadow = fetch_shadow(i, light.proj * in.world_position);
        let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
        let diffuse = max(0.0, dot(normal, light_dir));
        color += shadow * diffuse * light.color.xyz;
    }
    return vec4<f32>(color, 1.0) * u_entity.color;
}
"
OpMemberName %9 0 "view_proj"
OpMemberName %9 1 "num_lights"
OpName %9 "Globals"
OpMemberName %10 0 "world"
OpMemberName %10 1 "color"
OpName %10 "Entity"
OpMemberName %12 0 "proj_position"
OpMemberName %12 1 "world_normal"
OpMemberName %12 2 "world_position"
OpName %12 "VertexOutput"
OpMemberName %16 0 "proj"
OpMemberName %16 1 "pos"
OpMemberName %16 2 "color"
OpName %16 "Light"
OpName %24 "c_ambient"
OpName %19 "c_max_lights"
OpName %25 "u_globals"
OpName %28 "u_entity"
OpName %31 "s_lights"
OpName %34 "u_lights"
OpName %37 "t_shadow"
OpName %39 "sampler_shadow"
OpName %42 "light_id"
OpName %43 "homogeneous_coords"
OpName %44 "fetch_shadow"
OpName %75 "position"
OpName %78 "normal"
OpName %80 "proj_position"
OpName %82 "world_normal"
OpName %84 "world_position"
OpName %85 "vs_main"
OpName %92 "out"
OpName %134 "proj_position"
OpName %137 "world_normal"
OpName %140 "world_position"
OpName %143 "fs_main"
OpName %150 "color"
OpName %151 "i"
OpName %166 "loop_bound"
OpName %221 "proj_position"
OpName %223 "world_normal"
OpName %225 "world_position"
OpName %228 "fs_main_without_storage"
OpName %235 "color"
OpName %236 "i"
OpName %244 "loop_bound"
OpMemberDecorate %9 0 Offset 0
OpMemberDecorate %9 0 ColMajor
OpMemberDecorate %9 0 MatrixStride 16
OpMemberDecorate %9 1 Offset 64
OpMemberDecorate %10 0 Offset 0
OpMemberDecorate %10 0 ColMajor
OpMemberDecorate %10 0 MatrixStride 16
OpMemberDecorate %10 1 Offset 64
OpMemberDecorate %12 0 Offset 0
OpMemberDecorate %12 1 Offset 16
OpMemberDecorate %12 2 Offset 32
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 0 ColMajor
OpMemberDecorate %16 0 MatrixStride 16
OpMemberDecorate %16 1 Offset 64
OpMemberDecorate %16 2 Offset 80
OpDecorate %17 ArrayStride 96
OpDecorate %18 ArrayStride 96
OpDecorate %25 DescriptorSet 0
OpDecorate %25 Binding 0
OpDecorate %26 Block
OpMemberDecorate %26 0 Offset 0
OpDecorate %28 DescriptorSet 1
OpDecorate %28 Binding 0
OpDecorate %29 Block
OpMemberDecorate %29 0 Offset 0
OpDecorate %31 NonWritable
OpDecorate %31 DescriptorSet 0
OpDecorate %31 Binding 1
OpDecorate %32 Block
OpMemberDecorate %32 0 Offset 0
OpDecorate %34 DescriptorSet 0
OpDecorate %34 Binding 1
OpDecorate %35 Block
OpMemberDecorate %35 0 Offset 0
OpDecorate %37 DescriptorSet 0
OpDecorate %37 Binding 2
OpDecorate %39 DescriptorSet 0
OpDecorate %39 Binding 3
OpDecorate %75 Location 0
OpDecorate %78 Location 1
OpDecorate %80 BuiltIn Position
OpDecorate %82 Location 0
OpDecorate %84 Location 1
OpDecorate %134 BuiltIn FragCoord
OpDecorate %137 Location 0
OpDecorate %140 Location 1
OpDecorate %142 Location 0
OpDecorate %221 BuiltIn FragCoord
OpDecorate %223 Location 0
OpDecorate %225 Location 1
OpDecorate %227 Location 0
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%6 = OpTypeVector %4 4
%5 = OpTypeMatrix %6 4
%7 = OpTypeInt 32 0
%8 = OpTypeVector %7 4
%9 = OpTypeStruct %5 %8
%10 = OpTypeStruct %5 %6
%11 = OpTypeVector %4 3
%12 = OpTypeStruct %6 %11 %6
%14 = OpTypeInt 32 1
%13 = OpTypeVector %14 4
%15 = OpTypeMatrix %11 3
%16 = OpTypeStruct %5 %6 %6
%17 = OpTypeRuntimeArray %16
%19 = OpConstant  %7  10
%18 = OpTypeArray %16 %19
%20 = OpTypeImage %4 2D 1 1 0 1 Unknown
%21 = OpTypeSampler
%22 = OpTypeVector %4 2
%23 = OpConstant  %4  0.05
%24 = OpConstantComposite  %11  %23 %23 %23
%26 = OpTypeStruct %9
%27 = OpTypePointer Uniform %26
%25 = OpVariable  %27  Uniform
%29 = OpTypeStruct %10
%30 = OpTypePointer Uniform %29
%28 = OpVariable  %30  Uniform
%32 = OpTypeStruct %17
%33 = OpTypePointer StorageBuffer %32
%31 = OpVariable  %33  StorageBuffer
%35 = OpTypeStruct %18
%36 = OpTypePointer Uniform %35
%34 = OpVariable  %36  Uniform
%38 = OpTypePointer UniformConstant %20
%37 = OpVariable  %38  UniformConstant
%40 = OpTypePointer UniformConstant %21
%39 = OpVariable  %40  UniformConstant
%45 = OpTypeFunction %4 %7 %6
%48 = OpConstant  %4  0.0
%49 = OpConstant  %4  1.0
%50 = OpConstant  %4  0.5
%51 = OpConstant  %4  -0.5
%52 = OpConstantComposite  %22  %50 %51
%53 = OpConstantComposite  %22  %50 %50
%56 = OpTypeBool
%69 = OpTypeSampledImage %20
%76 = OpTypePointer Input %13
%75 = OpVariable  %76  Input
%78 = OpVariable  %76  Input
%81 = OpTypePointer Output %6
%80 = OpVariable  %81  Output
%83 = OpTypePointer Output %11
%82 = OpVariable  %83  Output
%84 = OpVariable  %81  Output
%86 = OpTypeFunction %2
%87 = OpTypePointer Uniform %9
%88 = OpConstant  %7  0
%90 = OpTypePointer Uniform %10
%93 = OpTypePointer Function %12
%94 = OpConstantNull  %12
%96 = OpTypePointer Uniform %5
%103 = OpTypePointer Function %11
%111 = OpTypeVector %14 3
%115 = OpConstant  %7  1
%117 = OpTypePointer Function %6
%118 = OpConstant  %7  2
%126 = OpTypePointer Output %4
%135 = OpTypePointer Input %6
%134 = OpVariable  %135  Input
%138 = OpTypePointer Input %11
%137 = OpVariable  %138  Input
%140 = OpVariable  %135  Input
%142 = OpVariable  %81  Output
%146 = OpTypePointer StorageBuffer %17
%152 = OpTypePointer Function %7
%160 = OpTypeVector %7 2
%161 = OpTypePointer Function %160
%162 = OpTypeVector %56 2
%163 = OpConstantComposite  %160  %88 %88
%164 = OpConstant  %7  4294967295
%165 = OpConstantComposite  %160  %164 %164
%178 = OpTypePointer Uniform %8
%179 = OpTypePointer Uniform %7
%189 = OpTypePointer StorageBuffer %16
%215 = OpTypePointer Uniform %6
%221 = OpVariable  %135  Input
%223 = OpVariable  %138  Input
%225 = OpVariable  %135  Input
%227 = OpVariable  %81  Output
%231 = OpTypePointer Uniform %18
%265 = OpTypePointer Uniform %16
%44 = OpFunction  %4  None %45
%42 = OpFunctionParameter  %7
%43 = OpFunctionParameter  %6
%41 = OpLabel
%46 = OpLoad  %20  %37
%47 = OpLoad  %21  %39
OpBranch %54
%54 = OpLabel
OpLine %3 68 9
%55 = OpCompositeExtract  %4  %43 3
OpLine %3 68 9
%57 = OpFOrdLessThanEqual  %56  %55 %48
OpLine %3 68 5
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %58
%59 = OpLabel
OpReturnValue %49
%58 = OpLabel
OpLine %3 72 27
OpLine %3 74 33
%60 = OpCompositeExtract  %4  %43 3
OpLine %3 74 27
%61 = OpFDiv  %4  %49 %60
OpLine %3 75 23
%62 = OpVectorShuffle  %22  %43 %43 0 1
%63 = OpFMul  %22  %62 %52
%64 = OpVectorTimesScalar  %22  %63 %61
OpLine %3 75 23
%65 = OpFAdd  %22  %64 %53
OpLine %3 77 12
%66 = OpBitcast  %14  %42
%67 = OpCompositeExtract  %4  %43 2
%68 = OpFMul  %4  %67 %61
%70 = OpConvertSToF  %4  %66
%71 = OpCompositeConstruct  %11  %65 %70
%72 = OpSampledImage  %69  %46 %47
%73 = OpImageSampleDrefExplicitLod  %4  %72 %71 %68 Lod %48
OpReturnValue %73
OpFunctionEnd
%85 = OpFunction  %2  None %86
%74 = OpLabel
%92 = OpVariable  %93  Function %94
%77 = OpLoad  %13  %75
%79 = OpLoad  %13  %78
%89 = OpAccessChain  %87  %25 %88
%91 = OpAccessChain  %90  %28 %88
OpBranch %95
%95 = OpLabel
OpLine %3 37 13
%97 = OpAccessChain  %96  %91 %88
%98 = OpLoad  %5  %97
OpLine %3 38 21
%99 = OpAccessChain  %96  %91 %88
%100 = OpLoad  %5  %99
%101 = OpConvertSToF  %6  %77
%102 = OpMatrixTimesVector  %6  %100 %101
OpLine %3 40 5
OpLine %3 40 36
%104 = OpCompositeExtract  %6  %98 0
%105 = OpVectorShuffle  %11  %104 %104 0 1 2
OpLine %3 40 46
%106 = OpCompositeExtract  %6  %98 1
%107 = OpVectorShuffle  %11  %106 %106 0 1 2
OpLine %3 40 24
%108 = OpCompositeExtract  %6  %98 2
%109 = OpVectorShuffle  %11  %108 %108 0 1 2
%110 = OpCompositeConstruct  %15  %105 %107 %109
%112 = OpVectorShuffle  %111  %79 %79 0 1 2
%113 = OpConvertSToF  %11  %112
%114 = OpMatrixTimesVector  %11  %110 %113
OpLine %3 40 5
%116 = OpAccessChain  %103  %92 %115
OpStore %116 %114
OpLine %3 41 5
OpLine %3 41 5
%119 = OpAccessChain  %117  %92 %118
OpStore %119 %102
OpLine %3 42 5
OpLine %3 42 25
%120 = OpAccessChain  %96  %89 %88
%121 = OpLoad  %5  %120
%122 = OpMatrixTimesVector  %6  %121 %102
OpLine %3 42 5
%123 = OpAccessChain  %117  %92 %88
OpStore %123 %122
OpLine %3 1 1
%124 = OpLoad  %12  %92
%125 = OpCompositeExtract  %6  %124 0
OpStore %80 %125
%127 = OpAccessChain  %126  %80 %115
%128 = OpLoad  %4  %127
%129 = OpFNegate  %4  %128
OpStore %127 %129
%130 = OpCompositeExtract  %11  %124 1
OpStore %82 %130
%131 = OpCompositeExtract  %6  %124 2
OpStore %84 %131
OpReturn
OpFunctionEnd
%143 = OpFunction  %2  None %86
%132 = OpLabel
%150 = OpVariable  %103  Function %24
%151 = OpVariable  %152  Function %88
%166 = OpVariable  %161  Function %163
%136 = OpLoad  %6  %134
%139 = OpLoad  %11  %137
%141 = OpLoad  %6  %140
%133 = OpCompositeConstruct  %12  %136 %139 %141
%144 = OpAccessChain  %87  %25 %88
%145 = OpAccessChain  %90  %28 %88
%147 = OpAccessChain  %146  %31 %88
%148 = OpLoad  %20  %37
%149 = OpLoad  %21  %39
OpBranch %153
%153 = OpLabel
OpLine %3 85 18
%154 = OpCompositeExtract  %11  %133 1
%155 = OpExtInst  %11  %1 Normalize %154
OpBranch %156
%156 = OpLabel
OpLine %3 88 5
OpLoopMerge %157 %159 None
OpBranch %167
%167 = OpLabel
%168 = OpLoad  %160  %166
%169 = OpIEqual  %162  %165 %168
%170 = OpAll  %56  %169
OpSelectionMerge %171 None
OpBranchConditional %170 %157 %171
%171 = OpLabel
%172 = OpCompositeExtract  %7  %168 1
%173 = OpIEqual  %56  %172 %164
%174 = OpSelect  %7  %173 %115 %88
%175 = OpCompositeConstruct  %160  %174 %115
%176 = OpIAdd  %160  %168 %175
OpStore %166 %176
OpBranch %158
%158 = OpLabel
OpLine %3 1 1
%177 = OpLoad  %7  %151
OpLine %3 88 29
%180 = OpAccessChain  %179  %144 %115 %88
%181 = OpLoad  %7  %180
OpLine %3 88 21
%182 = OpExtInst  %7  %1 UMin %181 %19
%183 = OpULessThan  %56  %177 %182
OpLine %3 88 20
OpSelectionMerge %184 None
OpBranchConditional %183 %184 %185
%185 = OpLabel
OpBranch %157
%184 = OpLabel
OpBranch %186
%186 = OpLabel
OpLine %3 89 21
%188 = OpLoad  %7  %151
%190 = OpAccessChain  %189  %147 %188
%191 = OpLoad  %16  %190
OpLine %3 91 38
%192 = OpLoad  %7  %151
%193 = OpCompositeExtract  %5  %191 0
%194 = OpCompositeExtract  %6  %133 2
%195 = OpMatrixTimesVector  %6  %193 %194
OpLine %3 91 22
%196 = OpFunctionCall  %4  %44 %192 %195
OpLine %3 93 25
%197 = OpCompositeExtract  %6  %191 1
%198 = OpVectorShuffle  %11  %197 %197 0 1 2
%199 = OpCompositeExtract  %6  %133 2
%200 = OpVectorShuffle  %11  %199 %199 0 1 2
%201 = OpFSub  %11  %198 %200
%202 = OpExtInst  %11  %1 Normalize %201
OpLine %3 94 23
%203 = OpDot  %4  %155 %202
%204 = OpExtInst  %4  %1 FMax %48 %203
OpLine %3 96 9
%205 = OpFMul  %4  %196 %204
%206 = OpCompositeExtract  %6  %191 2
%207 = OpVectorShuffle  %11  %206 %206 0 1 2
%208 = OpVectorTimesScalar  %11  %207 %205
%209 = OpLoad  %11  %150
%210 = OpFAdd  %11  %209 %208
OpLine %3 96 9
OpStore %150 %210
OpBranch %187
%187 = OpLabel
OpBranch %159
%159 = OpLabel
OpLine %3 88 68
%211 = OpLoad  %7  %151
%212 = OpIAdd  %7  %211 %115
OpLine %3 88 68
OpStore %151 %212
OpBranch %156
%157 = OpLabel
OpLine %3 1 1
%213 = OpLoad  %11  %150
OpLine %3 99 12
%214 = OpCompositeConstruct  %6  %213 %49
OpLine %3 99 12
%216 = OpAccessChain  %215  %145 %115
%217 = OpLoad  %6  %216
%218 = OpFMul  %6  %214 %217
OpStore %142 %218
OpReturn
OpFunctionEnd
%228 = OpFunction  %2  None %86
%219 = OpLabel
%235 = OpVariable  %103  Function %24
%236 = OpVariable  %152  Function %88
%244 = OpVariable  %161  Function %163
%222 = OpLoad  %6  %221
%224 = OpLoad  %11  %223
%226 = OpLoad  %6  %225
%220 = OpCompositeConstruct  %12  %222 %224 %226
%229 = OpAccessChain  %87  %25 %88
%230 = OpAccessChain  %90  %28 %88
%232 = OpAccessChain  %231  %34 %88
%233 = OpLoad  %20  %37
%234 = OpLoad  %21  %39
OpBranch %237
%237 = OpLabel
OpLine %3 105 18
%238 = OpCompositeExtract  %11  %220 1
%239 = OpExtInst  %11  %1 Normalize %238
OpBranch %240
%240 = OpLabel
OpLine %3 107 5
OpLoopMerge %241 %243 None
OpBranch %245
%245 = OpLabel
%246 = OpLoad  %160  %244
%247 = OpIEqual  %162  %165 %246
%248 = OpAll  %56  %247
OpSelectionMerge %249 None
OpBranchConditional %248 %241 %249
%249 = OpLabel
%250 = OpCompositeExtract  %7  %246 1
%251 = OpIEqual  %56  %250 %164
%252 = OpSelect  %7  %251 %115 %88
%253 = OpCompositeConstruct  %160  %252 %115
%254 = OpIAdd  %160  %246 %253
OpStore %244 %254
OpBranch %242
%242 = OpLabel
OpLine %3 1 1
%255 = OpLoad  %7  %236
OpLine %3 107 29
%256 = OpAccessChain  %179  %229 %115 %88
%257 = OpLoad  %7  %256
OpLine %3 107 21
%258 = OpExtInst  %7  %1 UMin %257 %19
%259 = OpULessThan  %56  %255 %258
OpLine %3 107 20
OpSelectionMerge %260 None
OpBranchConditional %259 %260 %261
%261 = OpLabel
OpBranch %241
%260 = OpLabel
OpBranch %262
%262 = OpLabel
OpLine %3 110 21
%264 = OpLoad  %7  %236
%266 = OpAccessChain  %265  %232 %264
%267 = OpLoad  %16  %266
OpLine %3 111 38
%268 = OpLoad  %7  %236
%269 = OpCompositeExtract  %5  %267 0
%270 = OpCompositeExtract  %6  %220 2
%271 = OpMatrixTimesVector  %6  %269 %270
OpLine %3 111 22
%272 = OpFunctionCall  %4  %44 %268 %271
OpLine %3 112 25
%273 = OpCompositeExtract  %6  %267 1
%274 = OpVectorShuffle  %11  %273 %273 0 1 2
%275 = OpCompositeExtract  %6  %220 2
%276 = OpVectorShuffle  %11  %275 %275 0 1 2
%277 = OpFSub  %11  %274 %276
%278 = OpExtInst  %11  %1 Normalize %277
OpLine %3 113 23
%279 = OpDot  %4  %239 %278
%280 = OpExtInst  %4  %1 FMax %48 %279
OpLine %3 114 9
%281 = OpFMul  %4  %272 %280
%282 = OpCompositeExtract  %6  %267 2
%283 = OpVectorShuffle  %11  %282 %282 0 1 2
%284 = OpVectorTimesScalar  %11  %283 %281
%285 = OpLoad  %11  %235
%286 = OpFAdd  %11  %285 %284
OpLine %3 114 9
OpStore %235 %286
OpBranch %263
%263 = OpLabel
OpBranch %243
%243 = OpLabel
OpLine %3 107 68
%287 = OpLoad  %7  %236
%288 = OpIAdd  %7  %287 %115
OpLine %3 107 68
OpStore %236 %288
OpBranch %240
%241 = OpLabel
OpLine %3 1 1
%289 = OpLoad  %11  %235
OpLine %3 116 12
%290 = OpCompositeConstruct  %6  %289 %49
OpLine %3 116 12
%291 = OpAccessChain  %215  %230 %115
%292 = OpLoad  %6  %291
%293 = OpFMul  %6  %290 %292
OpStore %227 %293
OpReturn
OpFunctionEnd