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

struct Particle
{
    vec3 position;
    vec3 previousPosition;
    vec3 rotation;
    vec3 previousRotation;
    uint flags;
    float lifetime;
    float targetLifetime;
    float size;
    uint triangleIndex;
};

struct FlrInput
{
    uint invocation_index;
};

struct ParticleEmitterSimulationData
{
    float gravity;
    float inverse_time_to_return_to_origin;
    float damping;
    float velocity_scale_over_lifetime;
    float rotations_over_lifetime;
    float rotations_over_lifetime_alignment_x;
    float rotations_over_lifetime_alignment_y;
    float rotations_over_lifetime_alignment_z;
    float collision_timeout;
    uint collision_material_mask;
    float collision_offset;
    float collision_restitution;
    float collision_restitution_XZ;
    float collision_angular_restitution;
    float light_radius;
    float light_intensity;
    float light_sphere_radius;
    float light_spawn_radius;
    float padding0;
    float padding1;
};

struct ParticleCompressed
{
    uvec4 particle_data_0;
    uvec4 particle_data_1;
    uvec4 particle_data_2;
};

struct ParticleExtensionCompressed
{
    uvec4 particle_data_0;
    uvec4 particle_data_1;
};

struct ParticleExtension
{
    float fieldWeight;
    float mass;
    uint color;
    uint skinningIndex;
    vec3 spawnPosition;
    uvec4 skinningIndices;
    vec4 skinningWeights;
};

struct MaterialData
{
    uvec4 paramIntData0;
    vec4 paramFloatData0;
    vec4 paramFloatData1;
    vec4 paramFloatData2;
    vec4 paramFloatData3;
    vec4 paramFloatData4;
    vec4 paramFloatData5;
    vec4 paramFloatData6;
    vec4 paramFloatData7;
    vec4 paramFloatData8;
    vec4 paramFloatData9;
    uvec4 paramImgIDs0;
    uvec4 paramImgIDs1;
    uvec4 paramImgIDs2;
};

// 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 = 8, std430) buffer SkinningBuffer
{
    mat3x4 _SkinningBuffer[];
} _337;

layout(set = 0, binding = 6, std430) buffer ParticleEmitterSimulationDataBuffer
{
    ParticleEmitterSimulationData _ParticleEmitterSimulationDataBuffer[];
} _426;

layout(set = 0, binding = 1, std140) uniform PerInstance
{
    uvec4 parameters_0;
    uvec4 parameters_1;
    vec4 parameters_2;
    uvec4 parameters_3;
    mat4 ubo_world_matrix;
    mat4 ubo_spawn_world_matrix;
} _430;

layout(set = 0, binding = 4, std430) buffer ParticleBuffer
{
    ParticleCompressed _ParticleBuffer[];
} _498;

layout(set = 0, binding = 2, std430) buffer FreeParticleIndexBuffer
{
    uint _FreeParticleIndexBuffer[];
} _639;

layout(set = 0, binding = 3, std430) buffer ParticleIndexBuffer
{
    uint _ParticleIndexBuffer[];
} _656;

layout(set = 0, binding = 5, std430) buffer ParticleExtensionBuffer
{
    ParticleExtensionCompressed _ParticleExtensionBuffer[];
} _686;

layout(set = 0, binding = 7, std430) buffer OverLifetimeBuffer
{
    uint _OverLifetimeBuffer[];
} _910;

layout(set = 0, binding = 0, std140) uniform PerView
{
    mat4 viewProjMatrix;
    vec4 cameraPositionWS;
    vec4 nearFar;
    vec4 dynamicResolutionParameters;
} _1065;

layout(set = 0, binding = 10, std430) buffer materialDataBuffer
{
    MaterialData _materialDataBuffer[];
} _1147;

layout(set = 0, binding = 9, std430) buffer LightsBuffer
{
    uint _LightsBuffer[];
} _1553;

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

layout(set = 0, binding = 13) uniform sampler2D motionVectorsTex;
layout(set = 0, binding = 11) uniform sampler2D depthBufferTex;
layout(set = 0, binding = 12) uniform sampler2D normalsTex;
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;

vec4 unpackFloat4(uint p_value, float p_factor, float p_lowerLimit)
{
    vec4 result = vec4(0.0);
    result.w = float((p_value >> uint(24)) & 255u);
    result.z = float((p_value >> uint(16)) & 255u);
    result.y = float((p_value >> uint(8)) & 255u);
    result.x = float(p_value & 255u);
    result = clamp(result / vec4(p_factor), vec4(p_lowerLimit), vec4(min(255.0, p_lowerLimit + 255.0)));
    return result;
}

uint getBlendIndex(uvec4 p_blendIndices, uint p_index)
{
    return p_blendIndices[p_index];
}

mat3x4 getSkinningMatrix(uint p_blendIndex, uint p_skinningBufferOffset)
{
    return _337._SkinningBuffer[(p_skinningBufferOffset * 256u) + p_blendIndex];
}

vec3 skinParticle(vec3 p_position, vec4 p_skinningWeights, uvec4 p_skinningIndices, uint p_skinningBufferOffset)
{
    vec3 skinnedPos = vec3(0.0);
    float accWeight = 0.0;
    for (uint boneIdx = 0u; boneIdx < 3u; boneIdx++)
    {
        float weight = p_skinningWeights[boneIdx];
        uvec4 param = p_skinningIndices;
        uint param_1 = boneIdx;
        uint blendIdx = getBlendIndex(param, param_1);
        uint param_2 = blendIdx;
        uint param_3 = p_skinningBufferOffset;
        mat3x4 skinningMat = getSkinningMatrix(param_2, param_3);
        skinnedPos += ((vec4(p_position, 1.0) * skinningMat) * weight);
        accWeight += weight;
    }
    uint param_4 = p_skinningIndices.w;
    uint param_5 = p_skinningBufferOffset;
    mat3x4 skinningMat_1 = getSkinningMatrix(param_4, param_5);
    skinnedPos += ((vec4(p_position, 1.0) * skinningMat_1) * (1.0 - accWeight));
    return skinnedPos;
}

vec3 integrateVerlet(float p_deltaT, vec3 p_curPosition, vec3 p_oldPosition, vec3 p_force, float p_dampingCoeff, float p_clockMultiplier, float p_timeCorrection0, float p_timeCorrection1)
{
    vec3 outputPos = p_curPosition;
    outputPos = (p_curPosition + (((p_curPosition - p_oldPosition) * (1.0 - (p_dampingCoeff * p_clockMultiplier))) * p_timeCorrection0)) + ((p_force * p_deltaT) * p_timeCorrection1);
    return outputPos;
}

float getOverLifetimeIndex(float p_percentage, uint p_index)
{
    return (p_percentage * 127.0) + float(p_index * 128u);
}

vec4 fromAngleAxis(vec3 p_axis, float p_angle)
{
    float halfAngle = 0.5 * p_angle;
    float s = sin(halfAngle);
    return vec4(s * p_axis.x, s * p_axis.y, s * p_axis.z, cos(halfAngle));
}

vec3 rotateVector(vec4 p_quat, vec3 p_vec)
{
    return p_vec + (cross(cross(p_vec, p_quat.xyz) + (p_vec * p_quat.w), p_quat.xyz) * 2.0);
}

uint decodeMaterialId(float source)
{
    return packSnorm2x16(vec2(source, 0.0));
}

float deviceDepthToLinear(float deviceDepth, float near, float far)
{
    return -((far * near) / ((deviceDepth * (far - near)) + near));
}

vec2 signNotZero(vec2 v)
{
    return vec2((v.x >= 0.0) ? 1.0 : (-1.0), (v.y >= 0.0) ? 1.0 : (-1.0));
}

vec3 decodeNormal(vec2 e)
{
    vec3 v = vec3(e, (1.0 - abs(e.x)) - abs(e.y));
    if (v.z < 0.0)
    {
        vec2 param = v.xy;
        vec2 _195 = (vec2(1.0) - abs(v.yx)) * signNotZero(param);
        v = vec3(_195.x, _195.y, v.z);
    }
    return normalize(v);
}

void reflectParticle(inout Particle p_p, vec3 p_normal, vec3 p_direction, float p_velocityLength, float p_restitution, float p_restitutionXZ)
{
    vec3 reflectionVector = reflect(p_direction, p_normal);
    float finalVel = p_velocityLength * p_restitution;
    vec3 normalAbs = abs(p_normal);
    float predominantAxisNormal = max(max(normalAbs.x, normalAbs.y), normalAbs.z);
    if (predominantAxisNormal != normalAbs.y)
    {
        finalVel *= p_restitutionXZ;
    }
    p_p.position = p_p.previousPosition + (reflectionVector * finalVel);
}

void simulate(uint p_particleIndex, uint p_offset)
{
    ParticleEmitterSimulationData ped;
    ped.gravity = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].gravity;
    ped.inverse_time_to_return_to_origin = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].inverse_time_to_return_to_origin;
    ped.damping = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].damping;
    ped.velocity_scale_over_lifetime = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].velocity_scale_over_lifetime;
    ped.rotations_over_lifetime = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].rotations_over_lifetime;
    ped.rotations_over_lifetime_alignment_x = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].rotations_over_lifetime_alignment_x;
    ped.rotations_over_lifetime_alignment_y = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].rotations_over_lifetime_alignment_y;
    ped.rotations_over_lifetime_alignment_z = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].rotations_over_lifetime_alignment_z;
    ped.collision_timeout = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_timeout;
    ped.collision_material_mask = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_material_mask;
    ped.collision_offset = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_offset;
    ped.collision_restitution = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_restitution;
    ped.collision_restitution_XZ = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_restitution_XZ;
    ped.collision_angular_restitution = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].collision_angular_restitution;
    ped.light_radius = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].light_radius;
    ped.light_intensity = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].light_intensity;
    ped.light_sphere_radius = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].light_sphere_radius;
    ped.light_spawn_radius = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].light_spawn_radius;
    ped.padding0 = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].padding0;
    ped.padding1 = _426._ParticleEmitterSimulationDataBuffer[_430.parameters_1.w].padding1;
    Particle p;
    p.position = uintBitsToFloat(_498._ParticleBuffer[p_particleIndex].particle_data_0.xyz);
    p.targetLifetime = unpackHalf2x16(_498._ParticleBuffer[p_particleIndex].particle_data_0.w & 65535u).x;
    p.triangleIndex = (_498._ParticleBuffer[p_particleIndex].particle_data_0.w >> uint(16)) & 65535u;
    p.previousPosition = uintBitsToFloat(_498._ParticleBuffer[p_particleIndex].particle_data_1.xyz);
    
    //p.previousPosition.x-= vk3d_params.stereo.x*11;
    //p.position.x-= vk3d_params.stereo.x*11;
    
    p.size = unpackHalf2x16(_498._ParticleBuffer[p_particleIndex].particle_data_1.w & 65535u).x;
    p.flags = (_498._ParticleBuffer[p_particleIndex].particle_data_1.w >> uint(16)) & 65535u;
    vec2 particleData2x = unpackHalf2x16(_498._ParticleBuffer[p_particleIndex].particle_data_2.x);
    vec2 particleData2y = unpackHalf2x16(_498._ParticleBuffer[p_particleIndex].particle_data_2.y);
    vec2 particleData2z = unpackHalf2x16(_498._ParticleBuffer[p_particleIndex].particle_data_2.z);
    p.rotation.x = particleData2x.x;
    p.rotation.y = particleData2x.y;
    p.rotation.z = particleData2y.x;
    p.previousRotation.x = particleData2y.y;
    p.previousRotation.y = particleData2z.x;
    p.previousRotation.z = particleData2z.y;
    p.lifetime = uintBitsToFloat(_498._ParticleBuffer[p_particleIndex].particle_data_2.w);
    vec3 particlePositionWS = vec3(0.0);
    float lifetimePerc = 0.0;
    ParticleExtension pe;
    MaterialData materialData;
    for (uint iterationIdx = 0u; iterationIdx < _430.parameters_3.x; iterationIdx++)
    {
        p.lifetime += _430.parameters_2.x;
        lifetimePerc = p.lifetime / max(p.targetLifetime, 9.9999999747524270787835121154785e-07);
        particlePositionWS = p.position;
        
        if ((_430.parameters_3.y & 8u) > 0u)
        {
            particlePositionWS = (_430.ubo_world_matrix * vec4(particlePositionWS, 1.0)).xyz;
        }
        
        bool _624 = lifetimePerc >= 1.0;
        bool _632;
        if (!_624)
        {
            _632 = particlePositionWS.y < (-50000.0);
        }
        else
        {
            _632 = _624;
        }
        if (_632)
        {
            uint _641 = atomicAdd(_639._FreeParticleIndexBuffer[0], 1u);
            uint offset = _641;
            _639._FreeParticleIndexBuffer[offset + 1u] = p_particleIndex;
            if (_430.parameters_1.y == 7u)
            {
                uint _661 = atomicAdd(_656._ParticleIndexBuffer[_430.parameters_0.y + 1u], 1u);
                uint offset_1 = _661;
            }
            return;
        }
        vec3 force = vec3(0.0, ped.gravity, 0.0);
        bool _671 = (_430.parameters_3.y & 32u) > 0u;
        bool _678;
        if (_671)
        {
            _678 = (p.flags & 1u) == 0u;
        }
        else
        {
            _678 = _671;
        }
        if (_678)
        {
            force = vec3(0.0);
            vec2 particleData0x = unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.x);
            pe.fieldWeight = particleData0x.x;
            pe.mass = particleData0x.y;
            pe.color = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.y;
            pe.skinningIndex = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.z;
            uint param = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.w;
            float param_1 = 1.0;
            float param_2 = 0.0;
            pe.skinningIndices = uvec4(unpackFloat4(param, param_1, param_2));
            pe.skinningWeights = vec4(unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.x), unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.y));
            pe.spawnPosition = vec3(unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.z), unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.w).x);
            vec3 spawnPosition = pe.spawnPosition;
            if ((_430.parameters_3.y & 256u) > 0u)
            {
                vec3 param_3 = pe.spawnPosition;
                vec4 param_4 = pe.skinningWeights;
                uvec4 param_5 = pe.skinningIndices;
                uint param_6 = _430.parameters_0.x;
                spawnPosition = skinParticle(param_3, param_4, param_5, param_6);
            }
            spawnPosition = (_430.ubo_spawn_world_matrix * vec4(spawnPosition, 1.0)).xyz;
            vec3 dist = spawnPosition - p.position;
            p.position += ((dist * _430.parameters_2.x) * ped.inverse_time_to_return_to_origin);
            if ((_430.parameters_3.y & 128u) > 0u)
            {
                p.previousPosition += ((dist * _430.parameters_2.x) * ped.inverse_time_to_return_to_origin);
            }
        }
        bool _811 = (_430.parameters_3.y & 8u) > 0u;
        bool _819;
        if (_811)
        {
            _819 = (_430.parameters_3.y & 16u) > 0u;
        }
        else
        {
            _819 = _811;
        }
        if (_819)
        {
            force = (_430.ubo_world_matrix * vec4(force, 0.0)).xyz;
        }
        float param_7 = _430.parameters_2.x;
        vec3 param_8 = p.position;
        vec3 param_9 = p.previousPosition;
        vec3 param_10 = force;
        float param_11 = ped.damping;
        float param_12 = _430.parameters_2.y;
        float param_13 = _430.parameters_2.z;
        float param_14 = _430.parameters_2.w;
        
        
        
        vec3 newPosition = integrateVerlet(param_7, param_8, param_9, param_10, param_11, param_12, param_13, param_14);
        p.previousPosition = p.position;
        
        //p.previousPosition.x-= vk3d_params.stereo.x*-1;
        
        p.position = newPosition;
        float param_15 = _430.parameters_2.x;
        vec3 param_16 = p.rotation;
        vec3 param_17 = p.previousRotation;
        vec3 param_18 = vec3(0.0);
        float param_19 = 0.0;
        float param_20 = _430.parameters_2.y;
        float param_21 = _430.parameters_2.z;
        float param_22 = _430.parameters_2.w;
        vec3 newRotation = integrateVerlet(param_15, param_16, param_17, param_18, param_19, param_20, param_21, param_22);
        p.previousRotation = p.rotation;
        p.rotation = newRotation;
        float param_23 = lifetimePerc;
        uint param_24 = 0u;
        float overLifetimeIndex0 = clamp(getOverLifetimeIndex(param_23, param_24), 0.0, 127.0);
        float param_25 = lifetimePerc;
        uint param_26 = 0u;
        float overLifetimeIndex1 = clamp(getOverLifetimeIndex(param_25, param_26) + 1.0, 0.0, 127.0);
        float interp = fract(overLifetimeIndex0);
        vec4 overLifetimeParams = (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex0)]) * (1.0 - interp)) + (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex1)]) * interp);
        float rotationValue = (overLifetimeParams.x * 2.0) - 1.0;
        if (abs(rotationValue) > 9.9999999747524270787835121154785e-07)
        {
            float val = ((rotationValue * 3.1415927410125732421875) * ped.rotations_over_lifetime) * _430.parameters_2.x;
            vec3 rotationsOverLifetimeAlignment = vec3(ped.rotations_over_lifetime_alignment_x, ped.rotations_over_lifetime_alignment_y, ped.rotations_over_lifetime_alignment_z);
            vec4 rotationQuat = vec4(0.0);
            float rotation = length(rotationsOverLifetimeAlignment);
            if (rotation > 9.9999999747524270787835121154785e-07)
            {
                vec3 param_27 = normalize(rotationsOverLifetimeAlignment);
                float param_28 = rotation;
                rotationQuat = fromAngleAxis(param_27, param_28);
            }
            vec4 param_29 = rotationQuat;
            vec3 param_30 = rotationsOverLifetimeAlignment;
            p.rotation += (rotateVector(param_29, param_30) * val);
            vec4 param_31 = rotationQuat;
            vec3 param_32 = rotationsOverLifetimeAlignment;
            p.previousRotation += (rotateVector(param_31, param_32) * val);
        }
        float velocityValue = (overLifetimeParams.y * 2.0) - 1.0;
        if (abs(velocityValue) > 9.9999999747524270787835121154785e-07)
        {
            vec3 particleVel = p.position - p.previousPosition;
            float particleVelLen = length(particleVel);
            if (particleVelLen > 9.9999999747524270787835121154785e-07)
            {
                vec3 vol = (particleVel * (1.0 / particleVelLen)) * ((velocityValue * ped.velocity_scale_over_lifetime) * _430.parameters_2.x);
                float volLen = length(vol);
                if (particleVelLen < volLen)
                {
                    p.position = p.previousPosition;
                }
                else
                {
                    p.position += vol;
                }
            }
        }
        bool _1051 = (_430.parameters_3.y & 1u) > 0u;
        bool _1059;
        if (_1051)
        {
            _1059 = p.lifetime > ped.collision_timeout;
        }
        else
        {
            _1059 = _1051;
        }
        if (_1059)
        {
            vec4 particlePositionClipSpace = _1065.viewProjMatrix * vec4(particlePositionWS, 1.0);
            particlePositionClipSpace /= vec4(particlePositionClipSpace.w);
            vec2 screenUv = (particlePositionClipSpace.xy * 0.5) + vec2(0.5);
            screenUv *= _1065.dynamicResolutionParameters.xy;
            bool _1095 = screenUv.x >= 0.0;
            bool _1101;
            if (_1095)
            {
                _1101 = screenUv.x <= 1.0;
            }
            else
            {
                _1101 = _1095;
            }
            bool _1107;
            if (_1101)
            {
                _1107 = screenUv.y >= 0.0;
            }
            else
            {
                _1107 = _1101;
            }
            bool _1113;
            if (_1107)
            {
                _1113 = screenUv.y <= 1.0;
            }
            else
            {
                _1113 = _1107;
            }
            bool _1119;
            if (_1113)
            {
                _1119 = particlePositionClipSpace.z >= 0.0;
            }
            else
            {
                _1119 = _1113;
            }
            bool _1125;
            if (_1119)
            {
                _1125 = particlePositionClipSpace.z <= 1.0;
            }
            else
            {
                _1125 = _1119;
            }
            bool onScreen = _1125;
            if (onScreen)
            {
                float param_33 = textureLod(motionVectorsTex, screenUv, 0.0).z;
                uint materialId = decodeMaterialId(param_33);
                uint _1150 = clamp(materialId, 0u, 4096u);
                materialData.paramIntData0 = _1147._materialDataBuffer[_1150].paramIntData0;
                materialData.paramFloatData0 = _1147._materialDataBuffer[_1150].paramFloatData0;
                materialData.paramFloatData1 = _1147._materialDataBuffer[_1150].paramFloatData1;
                materialData.paramFloatData2 = _1147._materialDataBuffer[_1150].paramFloatData2;
                materialData.paramFloatData3 = _1147._materialDataBuffer[_1150].paramFloatData3;
                materialData.paramFloatData4 = _1147._materialDataBuffer[_1150].paramFloatData4;
                materialData.paramFloatData5 = _1147._materialDataBuffer[_1150].paramFloatData5;
                materialData.paramFloatData6 = _1147._materialDataBuffer[_1150].paramFloatData6;
                materialData.paramFloatData7 = _1147._materialDataBuffer[_1150].paramFloatData7;
                materialData.paramFloatData8 = _1147._materialDataBuffer[_1150].paramFloatData8;
                materialData.paramFloatData9 = _1147._materialDataBuffer[_1150].paramFloatData9;
                materialData.paramImgIDs0 = _1147._materialDataBuffer[_1150].paramImgIDs0;
                materialData.paramImgIDs1 = _1147._materialDataBuffer[_1150].paramImgIDs1;
                materialData.paramImgIDs2 = _1147._materialDataBuffer[_1150].paramImgIDs2;
                if ((ped.collision_material_mask & materialData.paramIntData0.z) > 0u)
                {
                    float depth = textureLod(depthBufferTex, screenUv, 0.0).x;
                    float param_34 = depth;
                    float param_35 = _1065.nearFar.x;
                    float param_36 = _1065.nearFar.y;
                    float linearDepth = deviceDepthToLinear(param_34, param_35, param_36);
                    float param_37 = particlePositionClipSpace.z;
                    float param_38 = _1065.nearFar.x;
                    float param_39 = _1065.nearFar.y;
                    float particleLinearDepth = deviceDepthToLinear(param_37, param_38, param_39);
                    bool _1222 = particleLinearDepth > (linearDepth - ped.collision_offset);
                    bool _1231;
                    if (_1222)
                    {
                        _1231 = (particleLinearDepth - linearDepth) < ped.collision_offset;
                    }
                    else
                    {
                        _1231 = _1222;
                    }
                    if (_1231)
                    {
                        vec3 particleVel_1 = p.position - p.previousPosition;
                        float velocityLength = trunc(length(particleVel_1));
                        if (velocityLength > 9.9999999747524270787835121154785e-07)
                        {
                            vec3 particleDir = particleVel_1 / vec3(velocityLength);
                            vec2 param_40 = textureLod(normalsTex, screenUv, 0.0).xy;
                            vec3 worldSpaceNormal = decodeNormal(param_40);
                            Particle param_41 = p;
                            vec3 param_42 = worldSpaceNormal;
                            vec3 param_43 = particleDir;
                            float param_44 = velocityLength;
                            float param_45 = ped.collision_restitution;
                            float param_46 = ped.collision_restitution_XZ;
                            reflectParticle(param_41, param_42, param_43, param_44, param_45, param_46);
                            p = param_41;
                            if ((_430.parameters_3.y & 64u) > 0u)
                            {
                                p.flags |= 1u;
                            }
                            if ((_430.parameters_3.y & 4096u) > 0u)
                            {
                                p.flags |= 2u;
                            }
                        }
                        else
                        {
                            p.position = p.previousPosition;
                            p.flags |= 32u;
                        }
                        vec3 particleRot = p.rotation - p.previousRotation;
                        float rotationVel = length(particleRot);
                        if (rotationVel > 0.100000001490116119384765625)
                        {
                            p.previousRotation += (particleRot * ped.collision_angular_restitution);
                        }
                        else
                        {
                            p.previousRotation = p.rotation;
                        }
                    }
                }
            }
            else
            {
                if ((p.flags & 32u) > 0u)
                {
                    p.position = p.previousPosition;
                }
            }
        }
    }
    uvec3 _1347 = floatBitsToUint(p.position);
    _498._ParticleBuffer[p_particleIndex].particle_data_0 = uvec4(_1347.x, _1347.y, _1347.z, _498._ParticleBuffer[p_particleIndex].particle_data_0.w);
    _498._ParticleBuffer[p_particleIndex].particle_data_0.w = packHalf2x16(vec2(p.targetLifetime, 0.0)) | ((p.triangleIndex & 65535u) << 16u);
    uvec3 _1365 = floatBitsToUint(p.previousPosition);
    _498._ParticleBuffer[p_particleIndex].particle_data_1 = uvec4(_1365.x, _1365.y, _1365.z, _498._ParticleBuffer[p_particleIndex].particle_data_1.w);
    _498._ParticleBuffer[p_particleIndex].particle_data_1.w = packHalf2x16(vec2(p.size, 0.0)) | ((p.flags & 65535u) << 16u);
    _498._ParticleBuffer[p_particleIndex].particle_data_2.x = packHalf2x16(vec2(p.rotation.x, p.rotation.y));
    _498._ParticleBuffer[p_particleIndex].particle_data_2.y = packHalf2x16(vec2(p.rotation.z, p.previousRotation.x));
    _498._ParticleBuffer[p_particleIndex].particle_data_2.z = packHalf2x16(vec2(p.previousRotation.y, p.previousRotation.z));
    _498._ParticleBuffer[p_particleIndex].particle_data_2.w = floatBitsToUint(p.lifetime);
    bool _1412 = (_430.parameters_3.y & 2u) > 0u;
    bool _1419;
    if (_1412)
    {
        _1419 = (p.flags & 16u) > 0u;
    }
    else
    {
        _1419 = _1412;
    }
    if (_1419)
    {
        if (distance(_1065.cameraPositionWS.xyz, particlePositionWS) < ped.light_spawn_radius)
        {
            float param_47 = lifetimePerc;
            uint param_48 = 1u;
            float overLifetimeIndex0_1 = clamp(getOverLifetimeIndex(param_47, param_48), 128.0, 255.0);
            float param_49 = lifetimePerc;
            uint param_50 = 1u;
            float overLifetimeIndex1_1 = clamp(getOverLifetimeIndex(param_49, param_50) + 1.0, 128.0, 255.0);
            float interp_1 = fract(overLifetimeIndex0_1);
            vec4 colorOverLifetime = (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex0_1)]) * (1.0 - interp_1)) + (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex1_1)]) * interp_1);
            vec2 particleData0x_1 = unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.x);
            ParticleExtension pe_1;
            pe_1.fieldWeight = particleData0x_1.x;
            pe_1.mass = particleData0x_1.y;
            pe_1.color = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.y;
            pe_1.skinningIndex = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.z;
            uint param_51 = _686._ParticleExtensionBuffer[p_particleIndex].particle_data_0.w;
            float param_52 = 1.0;
            float param_53 = 0.0;
            pe_1.skinningIndices = uvec4(unpackFloat4(param_51, param_52, param_53));
            pe_1.skinningWeights = vec4(unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.x), unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.y));
            pe_1.spawnPosition = vec3(unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.z), unpackHalf2x16(_686._ParticleExtensionBuffer[p_particleIndex].particle_data_1.w).x);
            
            
            vec4 unpackedColor = unpackUnorm4x8(pe_1.color);
            vec3 finalLightColor = ((unpackedColor.xyz * unpackedColor.w) * colorOverLifetime.xyz) * colorOverLifetime.w;
            uint lightsBufferFrameOffset = _430.parameters_0.w * 321u;
            uint _1556 = atomicAdd(_1553._LightsBuffer[lightsBufferFrameOffset], 1u);
            uint prevValue = _1556;
            if (prevValue < 64u)
            {
                float param_54 = lifetimePerc;
                uint param_55 = 0u;
                float overLifetimeIndex0_2 = clamp(getOverLifetimeIndex(param_54, param_55), 0.0, 127.0);
                float param_56 = lifetimePerc;
                uint param_57 = 0u;
                float overLifetimeIndex1_2 = clamp(getOverLifetimeIndex(param_56, param_57) + 1.0, 0.0, 127.0);
                float interp_2 = fract(overLifetimeIndex0_2);
                vec4 overLifetimeParams2 = (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex0_2)]) * (1.0 - interp_2)) + (unpackUnorm4x8(_910._OverLifetimeBuffer[_430.parameters_1.z + uint(overLifetimeIndex1_2)]) * interp_2);
                float scaleOverLifetime = overLifetimeParams2.z;
                float lr = ped.light_radius * scaleOverLifetime;
                _1553._LightsBuffer[((lightsBufferFrameOffset + 1u) + (prevValue * 5u)) + 0u] = packHalf2x16(vec2(particlePositionWS.x, particlePositionWS.y));
                _1553._LightsBuffer[((lightsBufferFrameOffset + 1u) + (prevValue * 5u)) + 1u] = packHalf2x16(vec2(particlePositionWS.z, lr));
                _1553._LightsBuffer[((lightsBufferFrameOffset + 1u) + (prevValue * 5u)) + 2u] = packHalf2x16(vec2(finalLightColor.x, finalLightColor.y));
                _1553._LightsBuffer[((lightsBufferFrameOffset + 1u) + (prevValue * 5u)) + 3u] = packHalf2x16(vec2(finalLightColor.z, ped.light_intensity));
                _1553._LightsBuffer[((lightsBufferFrameOffset + 1u) + (prevValue * 5u)) + 4u] = packHalf2x16(vec2(ped.light_sphere_radius, 0.0));
            }
        }
    }
    if (_430.parameters_1.y == 7u)
    {
        uint _1682 = atomicAdd(_656._ParticleIndexBuffer[_430.parameters_0.z + 0u], 1u);
        uint offset_2 = _1682;
        _656._ParticleIndexBuffer[(_430.parameters_0.z + p_offset) + 4u] = p_particleIndex;
    }
    else
    {
        uint _1696 = atomicAdd(_656._ParticleIndexBuffer[_430.parameters_0.z + 0u], 1u);
        uint offset_3 = _1696;
        _656._ParticleIndexBuffer[(_430.parameters_0.z + offset_3) + 4u] = p_particleIndex;
    }
}

void flrMain(FlrInput flrInput)
{
    uint particleCount = _656._ParticleIndexBuffer[_430.parameters_0.y + 0u];
    if (flrInput.invocation_index < particleCount)
    {
        uint poolOffset = flrInput.invocation_index;
        if (_430.parameters_1.y == 7u)
        {
            poolOffset += _656._ParticleIndexBuffer[_430.parameters_0.y + 3u];
            poolOffset %= _430.parameters_1.x;
        }
        uint particleIndex = _656._ParticleIndexBuffer[(_430.parameters_0.y + poolOffset) + 4u];
        uint param = particleIndex;
        uint param_1 = poolOffset;
        simulate(param, param_1);
    }
}

void main()
{
    FlrInput flrInput;
    flrInput.invocation_index = gl_GlobalInvocationID.x;
    FlrInput param = flrInput;
    flrMain(param);
}


