// 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; }