//Culling CS 1?
#version 450
#extension GL_EXT_nonuniform_qualifier : require
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

struct FlrInput
{
    mat4 viewMatrix;
    mat4 projectionMatrix;
    vec4 frustumPlanes[6];
    uvec2 screenSize;
    uint mipLevelCount;
    uint instanceCount;
    uint invocation_index;
    vec3 mainViewPos;
    vec2 nearFarPlaneDistances;
};

struct CullingData
{
    vec4 worldBoundingSphere;
    vec4 aabbMin;
    vec4 aabbMax;
    uvec3 batchIndex;
    float renderDistance;
};

struct IndirectDrawData
{
    uint indexCount;
    uint instanceCount;
    uint firstIndex;
    uint vertexOffset;
    uint firstInstance;
};

struct IndirectionData
{
    uint globalInstanceIndex;
};

// Vk3DVision (http://3dsurroundgaming.com/) - Stereo Injection
layout(set = 0, binding = 110, std140) uniform Vk3DParams
{
    vec4 stereo;
    vec4 custom_params;
} vk3d_params;

layout(set = 0, binding = 3, std430) buffer InstanceCullingBuffer
{
    CullingData _InstanceCullingBuffer[];
} _42;

layout(set = 0, binding = 2, std430) buffer IndirectDrawBuffer
{
    IndirectDrawData _IndirectDrawBuffer[];
} _150;

layout(set = 0, binding = 1, std430) buffer IndirectionBuffer
{
    IndirectionData _IndirectionBuffer[];
} _176;

layout(set = 0, binding = 0, std140) uniform PerInstance
{
    mat4 viewMatrix;
    mat4 projectionMatrix;
    vec4 frustumPlanes[6];
    uvec4 instanceCount;
    vec4 mainViewPos;
    vec4 projParameters;
} _200;

layout(set = 0, binding = 102, std430) buffer DebugBuffer
{
    uint debugBuffer[];
} _272;

layout(set = 2, binding = 0) uniform texture2D globalTextures[];
layout(set = 2, binding = 0) uniform textureCube globalCubeTextures[];
layout(set = 2, binding = 0) uniform texture3D global3DTextures[];
layout(set = 1, binding = 0) uniform sampler linearClampSampler;
layout(set = 1, binding = 1) uniform sampler linearRepeatSampler;
layout(set = 1, binding = 2) uniform sampler nearestClampSampler;
layout(set = 1, binding = 3) uniform sampler nearestRepeatSampler;
layout(set = 1, binding = 4) uniform sampler shadowSampler;

void flrMain(FlrInput flrInput)
{
    if (flrInput.invocation_index >= flrInput.instanceCount)
    {
        return;
    }
    CullingData cullingData;
    cullingData.worldBoundingSphere = _42._InstanceCullingBuffer[flrInput.invocation_index].worldBoundingSphere;
    cullingData.aabbMin = _42._InstanceCullingBuffer[flrInput.invocation_index].aabbMin;
    cullingData.aabbMax = _42._InstanceCullingBuffer[flrInput.invocation_index].aabbMax;
    cullingData.batchIndex = _42._InstanceCullingBuffer[flrInput.invocation_index].batchIndex;
    cullingData.renderDistance = _42._InstanceCullingBuffer[flrInput.invocation_index].renderDistance;
    vec3 cameraWorldPosition = flrInput.mainViewPos;
    vec3 dist = cullingData.worldBoundingSphere.xyz - cameraWorldPosition;
    float squaredDistance = dot(dist, dist);
    if (squaredDistance > (cullingData.renderDistance * cullingData.renderDistance) && vk3d_params.custom_params.y!=1)
    {
        return;
    }
    uint visible = 0u;
    for (uint i = 0u; i < 6u; i++)
    {
        vec4 p = flrInput.frustumPlanes[i];
        float d = dot(p.xyz, cullingData.worldBoundingSphere.xyz) + p.w;
        visible |= (uint(d >= (-cullingData.worldBoundingSphere.w)) << i);
    }
    if (visible != 63u)
    {
        return;
    }
    uint indirectBatchOffset = cullingData.batchIndex.x;
    uint batchOffset = cullingData.batchIndex.y;
    uint indirectBatchSubMeshCount = cullingData.batchIndex.z;
    uint _154 = atomicAdd(_150._IndirectDrawBuffer[indirectBatchOffset].instanceCount, 1u);
    uint instanceIndex = _154;
    for (uint subMeshOffset = 1u; subMeshOffset < indirectBatchSubMeshCount; subMeshOffset++)
    {
        uint _169 = atomicAdd(_150._IndirectDrawBuffer[indirectBatchOffset + subMeshOffset].instanceCount, 1u);
        uint tempInstIdx = _169;
    }
    _176._IndirectionBuffer[batchOffset + instanceIndex].globalInstanceIndex = flrInput.invocation_index;
}

void main()
{
    FlrInput flrInput;
    flrInput.invocation_index = (gl_WorkGroupID.x * 64u) + gl_LocalInvocationID.x;
    flrInput.instanceCount = _200.instanceCount.x;
    flrInput.frustumPlanes[0] = _200.frustumPlanes[0];
    flrInput.frustumPlanes[1] = _200.frustumPlanes[1];
    flrInput.frustumPlanes[2] = _200.frustumPlanes[2];
    flrInput.frustumPlanes[3] = _200.frustumPlanes[3];
    flrInput.frustumPlanes[4] = _200.frustumPlanes[4];
    flrInput.frustumPlanes[5] = _200.frustumPlanes[5];
    flrInput.viewMatrix = _200.viewMatrix;
    flrInput.projectionMatrix = _200.projectionMatrix;
    flrInput.screenSize = _200.instanceCount.zw;
    flrInput.mainViewPos = _200.mainViewPos.xyz;
    flrInput.nearFarPlaneDistances = _200.projParameters.xy;
    FlrInput param = flrInput;
    flrMain(param);
}




