#version 430
layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in;

struct droplet_data_t
{
    vec2 pos[48];
    vec2 velocity;
    float quant;
    float regen_t;
    vec2 tail_v;
    float bump_t;
    float F_d_s_len;
    float bump_sz;
    float bump_rate;
    float bump_rate_upd_t;
    float tail_angle;
    float spd;
    uint streamer;
    float tail_upd_t;
    float pad;
};

#ifndef SPIRV_CROSS_CONSTANT_ID_0
#define SPIRV_CROSS_CONSTANT_ID_0 2048
#endif
const int DEPTH_TEX_SZ = SPIRV_CROSS_CONSTANT_ID_0;

struct droplet_tail_t
{
    vec2 pos;
    float quant;
    float pad;
};

struct droplet_vtx_t
{
    vec2 pos;
    vec2 ctr;
    float radius;
    float size;
    float pad[2];
};

const vec3 _904[9] = vec3[](vec3(0.0, 0.4000000059604644775390625, 1.0), vec3(0.803484499454498291015625, 0.1660444438457489013671875, 1.0), vec3(0.9848077297210693359375, -0.4263518154621124267578125, 1.0), vec3(0.649519026279449462890625, -1.10000002384185791015625, 1.0), vec3(0.2565151154994964599609375, -1.65969264507293701171875, 1.0), vec3(-0.2565151154994964599609375, -1.65969264507293701171875, 1.0), vec3(-0.649519026279449462890625, -1.10000002384185791015625, 1.0), vec3(-0.9848077297210693359375, -0.4263518154621124267578125, 1.0), vec3(-0.803484499454498291015625, 0.1660444438457489013671875, 1.0));

struct droplet_pixel_t
{
    vec2 pos;
    float depth;
};

layout(binding = 0, std430) buffer droplet_data
{
    droplet_data_t d[];
} droplets;

layout(binding = 2, std430) buffer droplet_tails
{
    droplet_tail_t t[];
} tails;

layout(binding = 1, std430) buffer droplet_vtx
{
    droplet_vtx_t v[];
} vertices;

layout(location = 4) uniform vec2 gravity_point;
layout(location = 5) uniform float gravity_force;
layout(location = 8) uniform vec2 thrust_point;
layout(location = 9) uniform float thrust_force;
layout(location = 6) uniform vec2 wind_point;
layout(location = 7) uniform float wind_force;
layout(location = 2) uniform float cur_t;
layout(location = 30) uniform float rand_seed[8];
layout(location = 3) uniform float d_t;
layout(location = 10) uniform float precip_intens;
layout(location = 11) uniform float min_droplet_sz;
layout(location = 1, binding = 0) uniform sampler2D ws_temp_tex;
layout(location = 12) uniform float le_temp;

bool droplet_should_exist(float quant, bool streamer)
{
    if (quant <= 0.0)
    {
        return false;
    }
    vec2 pos;
    if (streamer)
    {
        pos = droplets.d[gl_GlobalInvocationID.x].pos[47];
    }
    else
    {
        pos = droplets.d[gl_GlobalInvocationID.x].pos[0];
    }
    bool _1026 = pos.x > 0.0;
    bool _1032;
    if (_1026)
    {
        _1032 = pos.x < 1.0;
    }
    else
    {
        _1032 = _1026;
    }
    bool _1038;
    if (_1032)
    {
        _1038 = pos.y > 0.0;
    }
    else
    {
        _1038 = _1032;
    }
    bool _1044;
    if (_1038)
    {
        _1044 = pos.y < 1.0;
    }
    else
    {
        _1044 = _1038;
    }
    return _1044;
}

vec2 droplet_forces_integrate(vec2 old_pos)
{
    vec2 droplet_pos = old_pos;
    vec2 F_g = normalize(droplet_pos - gravity_point) * gravity_force;
    vec2 F_t = normalize(droplet_pos - thrust_point) * thrust_force;
    vec2 F_w = normalize(droplet_pos - wind_point) * wind_force;
    vec2 F_a = (F_g + F_t) + F_w;
    return F_a;
}

float gold_noise(vec2 coordinate, float seed)
{
    return fract(sin(dot(coordinate * (seed + 0.1618033945560455322265625), vec2(0.1618033945560455322265625, 0.31415927410125732421875))) * 14142.1357421875);
}

float update_static_drag_len(vec2 pos, float quant, float spd)
{
    float F_d_s_len = droplets.d[gl_GlobalInvocationID.x].F_d_s_len;
    float coeff_vel = clamp(spd, 0.0, 0.00999999977648258209228515625);
    float F_d_s_len_tgt = mix(7.5, 0.0, coeff_vel) / max(quant, 1.0);
    F_d_s_len = mix(F_d_s_len, F_d_s_len_tgt, d_t / 0.5);
    vec2 param = pos;
    float param_1 = rand_seed[2];
    float rand_val = gold_noise(param, param_1);
    float prob = mix(0.999000012874603271484375, 0.980000019073486328125, precip_intens);
    if (rand_val > prob)
    {
        F_d_s_len = 0.0;
    }
    return F_d_s_len;
}

vec2 bump_droplet(vec2 pos, float spd, vec2 velocity, out float bump_sz_out)
{
    float spd_fract = smoothstep(0.0, 0.20000000298023223876953125, spd);
    if ((cur_t - droplets.d[gl_GlobalInvocationID.x].bump_t) < 0.0500000007450580596923828125)
    {
        bump_sz_out = droplets.d[gl_GlobalInvocationID.x].bump_sz;
        return velocity;
    }
    droplets.d[gl_GlobalInvocationID.x].bump_t = cur_t;
    float spd_clamped = clamp(spd, 0.0, 1.0);
    float bump_prob = mix(0.25, 0.75, spd_clamped);
    vec2 param = pos;
    float param_1 = rand_seed[0];
    if (gold_noise(param, param_1) < (1.0 - bump_prob))
    {
        bump_sz_out = droplets.d[gl_GlobalInvocationID.x].bump_sz;
        return velocity;
    }
    vec2 param_2 = pos;
    float param_3 = rand_seed[1];
    float rand_val = gold_noise(param_2, param_3);
    float scale = mix(20.0, 1.0, spd_clamped) / float(DEPTH_TEX_SZ);
    float bump_sz = scale * (rand_val - 0.5);
    droplets.d[gl_GlobalInvocationID.x].bump_sz = bump_sz;
    bump_sz_out = bump_sz;
    return velocity * 0.699999988079071044921875;
}

float bump_rate_upd(vec2 pos)
{
    if ((cur_t - droplets.d[gl_GlobalInvocationID.x].bump_rate_upd_t) < 0.0500000007450580596923828125)
    {
        return droplets.d[gl_GlobalInvocationID.x].bump_rate;
    }
    vec2 param = pos;
    float param_1 = rand_seed[1];
    float new_rate = gold_noise(param, param_1);
    droplets.d[gl_GlobalInvocationID.x].bump_rate_upd_t = cur_t;
    droplets.d[gl_GlobalInvocationID.x].bump_rate = new_rate;
    return new_rate;
}

vec2 vec2_norm_right(vec2 v)
{
    return vec2(v.y, -v.x);
}

void streamer_upd_tail()
{
    if ((cur_t - droplets.d[gl_GlobalInvocationID.x].tail_upd_t) > 0.0500000007450580596923828125)
    {
        for (int i = 47; i > 0; i--)
        {
            droplets.d[gl_GlobalInvocationID.x].pos[i] = droplets.d[gl_GlobalInvocationID.x].pos[i - 1];
        }
        droplets.d[gl_GlobalInvocationID.x].tail_upd_t = cur_t;
    }
}

void update_droplet_tail_v(float spd, vec2 old_pos, vec2 new_pos, out vec2 new_tail)
{
    vec2 d_pos = new_pos - old_pos;
    float rate = 1.0 - clamp(smoothstep(0.0, 0.0199999995529651641845703125, spd), 0.0, 0.89999997615814208984375);
    d_pos = new_pos - old_pos;
    vec2 tail_v_tgt;
    if (any(notEqual(d_pos, vec2(0.0))))
    {
        tail_v_tgt = normalize(d_pos);
    }
    else
    {
        tail_v_tgt = vec2(0.0, -1.0);
    }
    vec2 tail_v = mix(droplets.d[gl_GlobalInvocationID.x].tail_v, tail_v_tgt, vec2(d_t / rate));
    droplets.d[gl_GlobalInvocationID.x].tail_v = tail_v;
    new_tail = tail_v;
}

void droplet_move(float quant, bool streamer, out vec2 new_pos_out, out float spd_out, out vec2 new_tail)
{
    float rel_quant = quant / 120.0;
    vec2 old_pos = droplets.d[gl_GlobalInvocationID.x].pos[0];
    vec2 velocity = droplets.d[gl_GlobalInvocationID.x].velocity;
    float spd = droplets.d[gl_GlobalInvocationID.x].spd;
    float spd_tgt = length(velocity);
    vec2 param = old_pos;
    vec2 F_a = droplet_forces_integrate(param);
    vec2 F_d_d = (-velocity) * 1.0;
    spd = mix(spd, spd_tgt, d_t / 0.20000000298023223876953125);
    vec2 param_1 = old_pos;
    float param_2 = quant;
    float param_3 = spd;
    float F_d_s_len = update_static_drag_len(param_1, param_2, param_3);
    vec2 F_d_s;
    if (F_d_s_len < length(F_a))
    {
        F_d_s = normalize(F_a) * (-F_d_s_len);
    }
    else
    {
        F_d_s = -F_a;
    }
    vec2 F = (F_a + F_d_d) + F_d_s;
    velocity += (F * d_t);
    vec2 param_4 = old_pos;
    float param_5 = spd;
    vec2 param_6 = velocity;
    float param_7;
    vec2 _528 = bump_droplet(param_4, param_5, param_6, param_7);
    float bump_sz = param_7;
    velocity = _528;
    vec2 new_pos = (velocity * d_t) + old_pos;
    if (bump_sz > 0.0)
    {
        vec2 param_8 = old_pos;
        float _543 = bump_rate_upd(param_8);
        float bump_rate = _543;
        vec2 param_9 = velocity;
        vec2 velocity_norm = vec2_norm_right(param_9);
        float displace = min((spd * d_t) * bump_rate, bump_sz);
        new_pos += (normalize(velocity_norm) * displace);
        bump_sz -= displace;
    }
    else
    {
        if (bump_sz < 0.0)
        {
            vec2 param_10 = old_pos;
            float _573 = bump_rate_upd(param_10);
            float bump_rate_1 = _573;
            vec2 param_11 = velocity;
            vec2 velocity_norm_1 = vec2_norm_right(param_11);
            float displace_1 = max(((-spd) * d_t) * bump_rate_1, bump_sz);
            new_pos += (normalize(velocity_norm_1) * displace_1);
            bump_sz -= displace_1;
        }
    }
    droplets.d[gl_GlobalInvocationID.x].bump_sz = bump_sz;
    if (streamer)
    {
        streamer_upd_tail();
        droplets.d[gl_GlobalInvocationID.x].pos[0] = new_pos;
    }
    else
    {
        droplets.d[gl_GlobalInvocationID.x].pos[1] = old_pos;
        droplets.d[gl_GlobalInvocationID.x].pos[0] = new_pos;
    }
    new_pos_out = new_pos;
    spd_out = spd;
    droplets.d[gl_GlobalInvocationID.x].velocity = velocity;
    droplets.d[gl_GlobalInvocationID.x].F_d_s_len = F_d_s_len;
    float param_12 = spd;
    vec2 param_13 = old_pos;
    vec2 param_14 = new_pos;
    vec2 param_15;
    update_droplet_tail_v(param_12, param_13, param_14, param_15);
    vec2 tail_v = param_15;
    new_tail = tail_v;
    droplets.d[gl_GlobalInvocationID.x].spd = spd;
    spd_out = spd;
}

mat3 mat3_scale(mat3 m, vec2 scale)
{
    mat3 scale_mat = mat3(vec3(scale.x, 0.0, 0.0), vec3(0.0, scale.y, 0.0), vec3(0.0, 0.0, 1.0));
    return scale_mat * m;
}

mat3 mat3_rotate_dir(mat3 m, vec2 dir)
{
    mat3 rotate_mat = mat3(vec3(dir.y, -dir.x, 0.0), vec3(dir.x, dir.y, 0.0), vec3(0.0, 0.0, 1.0));
    return rotate_mat * m;
}

void droplet_visual_construct(vec2 pos, float spd, float quant, bool streamer, vec2 tail_v)
{
    float spd_fract = clamp((spd - 0.0) / 0.100000001490116119384765625, 0.0, 1.0);
    float quant_vis = mix(quant, quant / 2.0, spd_fract);
    float quant_fract = quant_vis / 120.0;
    float radius = (10.0 * quant_fract) / float(DEPTH_TEX_SZ);
    vec2 scale_factor = mix(vec2(1.0), vec2(0.800000011920928955078125, 2.0), vec2(spd_fract)) * radius;
    mat3 param = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
    vec2 param_1 = scale_factor;
    mat3 param_2 = mat3_scale(param, param_1);
    vec2 param_3 = droplets.d[gl_GlobalInvocationID.x].tail_v;
    mat3 xform = mat3_rotate_dir(param_2, param_3);
    for (int i = 0; i < 9; i++)
    {
        vertices.v[(gl_GlobalInvocationID.x * 10u) + uint(i)].pos = vec2((xform * _904[i]).xy);
        vertices.v[(gl_GlobalInvocationID.x * 10u) + uint(i)].ctr = pos;
        vertices.v[(gl_GlobalInvocationID.x * 10u) + uint(i)].radius = radius;
        vertices.v[(gl_GlobalInvocationID.x * 10u) + uint(i)].size = radius;
    }
    vertices.v[(gl_GlobalInvocationID.x * 10u) + 9u].pos = vec2(0.0);
    vertices.v[(gl_GlobalInvocationID.x * 10u) + 9u].ctr = pos;
    vertices.v[(gl_GlobalInvocationID.x * 10u) + 9u].radius = 0.0;
    vertices.v[(gl_GlobalInvocationID.x * 10u) + 9u].size = radius;
    if (streamer)
    {
        for (int i_1 = 0; i_1 < 48; i_1++)
        {
            tails.t[((gl_GlobalInvocationID.x >> uint(4)) * 48u) + uint(i_1)].pos = droplets.d[gl_GlobalInvocationID.x].pos[i_1];
            tails.t[((gl_GlobalInvocationID.x >> uint(4)) * 48u) + uint(i_1)].quant = quant_vis * (1.0 - (float(i_1) / 48.0));
        }
    }
}

void droplet_init_velocity(vec2 droplet_pos)
{
    vec2 F_g = normalize(droplet_pos - gravity_point) * gravity_force;
    vec2 F_t = normalize(droplet_pos - thrust_point) * thrust_force;
    vec2 F_w = normalize(droplet_pos - wind_point) * wind_force;
    vec2 F_a = (F_g + F_t) + F_w;
    vec2 param = droplet_pos;
    float param_1 = rand_seed[3];
    droplets.d[gl_GlobalInvocationID.x].velocity = F_a * gold_noise(param, param_1);
}

void droplet_regen()
{
    if ((cur_t - droplets.d[gl_GlobalInvocationID.x].regen_t) < (0.5 + (float(gl_GlobalInvocationID.x) / 1024.0)))
    {
        return;
    }
    droplets.d[gl_GlobalInvocationID.x].regen_t = cur_t;
    vec2 coord = vec2(vec3(gl_GlobalInvocationID).xy);
    vec2 param = coord;
    float param_1 = rand_seed[4];
    if (gold_noise(param, param_1) >= precip_intens)
    {
        return;
    }
    vec2 param_2 = coord;
    float param_3 = rand_seed[5];
    vec2 param_4 = coord;
    float param_5 = rand_seed[6];
    vec2 droplet_pos = vec2(gold_noise(param_2, param_3), gold_noise(param_4, param_5));
    for (int i = 0; i < 48; i++)
    {
        droplets.d[gl_GlobalInvocationID.x].pos[i] = droplet_pos;
    }
    vec2 param_6 = coord;
    float param_7 = rand_seed[7];
    float droplet_sz_ratio = gold_noise(param_6, param_7);
    droplets.d[gl_GlobalInvocationID.x].quant = mix(min_droplet_sz, 120.0, droplet_sz_ratio);
    droplets.d[gl_GlobalInvocationID.x].bump_sz = 0.0;
    vec2 param_8 = droplet_pos;
    droplet_init_velocity(param_8);
    droplets.d[gl_GlobalInvocationID.x].streamer = uint((gl_GlobalInvocationID.x & 15u) == 0u);
    if (droplets.d[gl_GlobalInvocationID.x].streamer != 0u)
    {
        for (int i_1 = 0; i_1 < 48; i_1++)
        {
            tails.t[((gl_GlobalInvocationID.x >> uint(4)) * 48u) + uint(i_1)].pos = vec2(0.0);
        }
    }
}

void main()
{
    float new_quant = droplets.d[gl_GlobalInvocationID.x].quant - d_t;
    bool streamer = droplets.d[gl_GlobalInvocationID.x].streamer != 0u;
    float param = new_quant;
    bool param_1 = streamer;
    if (droplet_should_exist(param, param_1))
    {
        float param_2 = new_quant;
        bool param_3 = streamer;
        vec2 param_4;
        float param_5;
        vec2 param_6;
        droplet_move(param_2, param_3, param_4, param_5, param_6);
        vec2 pos = param_4;
        float spd = param_5;
        vec2 tail_v = param_6;
        vec2 param_7 = pos;
        float param_8 = spd;
        float param_9 = new_quant;
        bool param_10 = streamer;
        vec2 param_11 = tail_v;
        droplet_visual_construct(param_7, param_8, param_9, param_10, param_11);
        droplets.d[gl_GlobalInvocationID.x].quant = new_quant;
    }
    else
    {
        droplet_regen();
    }
}

