// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only


const uint particleSize = 4;

struct Particle
{
    vec3 position;
    float size;
    vec3 rotation;
    float age;
    vec4 color;
    vec3 center;
};

vec2 qt_indexToUV(in uint index)
{
    uint v = index / qt_countPerSlice;
    uint u = index - qt_countPerSlice * v;
    return (vec2(u * particleSize, v) + vec2(0.5)) * qt_oneOverParticleImageSize;
}

Particle qt_loadParticle(in uint index)
{
    Particle p;
    vec2 offset = qt_indexToUV(index);
    vec4 p0 = texture(qt_particleTexture, offset);
    vec4 p1 = texture(qt_particleTexture, vec2(offset.x + qt_oneOverParticleImageSize.x, offset.y));
    vec4 p2 = texture(qt_particleTexture, vec2(offset.x + 2.0 * qt_oneOverParticleImageSize.x, offset.y));
    vec4 p3 = texture(qt_particleTexture, vec2(offset.x + 3.0 * qt_oneOverParticleImageSize.x, offset.y));
    p.position = p0.xyz;
    p.size = p0.w;
    p.rotation = p1.xyz;
    p.age = p1.w;
    p.color = p2;
    p.center = p3.xyz;
    return p;
}

mat3 qt_fromEulerRotation(in vec3 rotation)
{
    float a = cos(rotation.x);
    float b = sin(rotation.x);
    float c = cos(rotation.y);
    float d = sin(rotation.y);
    float e = cos(rotation.z);
    float f = sin(rotation.z);
    mat3 ret;
    float bd = b * d;
    float ad = a * d;
    ret[0][0] = c * e;
    ret[0][1] = -c * f;
    ret[0][2] = d;
    ret[1][0] = bd * e + a * f;
    ret[1][1] = a * e - bd * f;
    ret[1][2] = -b * c;
    ret[2][0] = b * f - ad * e;
    ret[2][1] = ad * f + b * e;
    ret[2][2] = a * c;
    return ret;
}

vec3 qt_applyParticle(in vec3 position, in vec3 normal, in vec4 color, out vec3 outNormal, out vec4 outColor, in mat4 particleMatrix)
{
    uint index = (gl_VertexIndex + qt_particleIndexOffset) / 3;
    Particle p = qt_loadParticle(index);
    mat3 rotMat = qt_fromEulerRotation(p.rotation);
    vec3 particlePos = p.size * rotMat * (position - p.center);
    vec3 pos = particlePos + (particleMatrix * vec4(p.position, 1.0)).xyz;
    outNormal = normalize(rotMat * normal);
    outColor = color * p.color;
    return pos;
}
