This commit is contained in:
Gaël committed 2026-10-19 20:59:15 +02:00
commit 87bff164f1
416 files changed
+279512

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
#version 450
#extension GL_GOOGLE_include_directive : require
layout(local_size_x = 64) in;
#include "fx_common.glsl"
// Explosion sprites and flashes: advance, draw the animated sprite (centred) and add a fading light.
// One workgroup per animation record (the dispatch is FANIM_ALL groups): its 64 threads share the sprite's pixels. (One thread per record drew a big
// explosion sprite alone - 100 000 pixels and more - and three bombs took 15 ms of GPU time.)
void main() {
const uint id = gl_WorkGroupID.x, lane = gl_LocalInvocationID.x;
const bool drawOnly = pc.pass_ == 1; // between ticks nothing advances
if (gl_GlobalInvocationID.x == 0u && !drawOnly) lpad[0] = lpad[0] * 5u / 6u; // camera shake decays
if (id >= uint(FANIM_ALL)) return;
FAnim a = fanims[id];
barrier(); // (every lane has read the record before lane 0 advances it)
if (a.b.z <= 0) return;
int age = drawOnly ? a.b.y : a.b.y + 1;
if (age >= a.b.z) { if (!drawOnly && lane == 0u) fanims[id].b.z = 0; return; }
float k = 1.0 - float(age) / float(a.b.z);
if (!drawOnly && lane == 0u) {
fanims[id].b.y = age;
const float lk = a.c.y > 0.0 ? max(0.0, 1.0 - float(age) / a.c.y) : k; // (c.y: the light's own fade frames)
if (a.a.w > 0.0 && lk > 0.0) add_light(a.a.xy, a.a.z, a.a.w * lk, rgb_of(uint(a.b.w)));
}
if (a.b.x < 0) return;
int b = BOOM_BASE + a.b.x * BOOM_STRIDE;
ivec4 b0 = fti(b), b1 = fti(b + 1);
vec4 b3 = ftf(b + 3);
if (b0.y <= 0 || b0.z <= 0) return;
int frame = age / max(b1.x, 1);
if (frame >= b0.w) return;
// the sprite is placed with its pivot at the effect position and rotated by the angle (muzzle flashes point along the shot)
// c.z: a scale (0: 1; negative: drawn behind - only where no cell and no sprite is, the render_back sprite particles of the host, main.cpp); c.w: a tint (rgb) and alpha
// (bits 24-31) as bits (0: none); a host record (tinted) has its own y scale in c.y (the GPU's records keep their light's fade there)
const uint tw = floatBitsToUint(a.c.w);
const bool tinted = tw != 0u;
const float sx0 = a.c.z == 0.0 ? 1.0 : abs(a.c.z);
const vec2 sclv = max(vec2(sx0, tinted ? a.c.y : sx0), vec2(0.01));
const float scl = max(sclv.x, sclv.y);
const bool behind = a.c.z < 0.0;
const vec3 tint = vec3(float((tw >> 16) & 255u), float((tw >> 8) & 255u), float(tw & 255u)) / 255.0;
const float alpha = tinted ? float(tw >> 24) / 255.0 : 1.0;
vec2 pivot = b3.zw, size = vec2(b0.yz);
float ca = cos(a.c.x), sa = sin(a.c.x);
float r = (length(max(pivot, size - pivot)) + 1.5) * scl;
int n = int(2.0 * r) + 2;
ivec2 lo = ivec2(floor(a.a.xy - vec2(r)));
bool additive = (b1.w & 8) != 0;
for (int j = int(lane); j < n * n; j += 64) {
ivec2 w = lo + ivec2(j % n, j / n);
vec2 d = vec2(w) + 0.5 - a.a.xy;
ivec2 sp = ivec2(floor(pivot + vec2(ca * d.x + sa * d.y, -sa * d.x + ca * d.y) / sclv));
if (sp.x < 0 || sp.y < 0 || sp.x >= b0.y || sp.y >= b0.z) continue;
ivec2 q = w - ivec2(pc.view_x, pc.view_y);
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) continue;
uint t = fxtex[b0.x + frame * b0.y * b0.z + sp.y * b0.y + sp.x];
if ((t >> 24) == 0u) continue;
const int qi = q.y * pc.gw + q.x;
if (behind && (cell_mat(cells[qi]) != 0u || entlayer[qi] != 0u)) continue; // (behind the terrain and the sprites already drawn)
if (tinted) {
const vec3 c = vec3(float((t >> 16) & 255u), float((t >> 8) & 255u), float(t & 255u)) / 255.0 * tint;
const float al = float(t >> 24) / 255.0 * alpha;
if (al < 0.02) continue;
if (additive) t = 0x01000000u | packUnorm4x8(vec4(c.b * al, c.g * al, c.r * al, 0.0));
else t = (uint(al * 255.0) << 24) | (packUnorm4x8(vec4(c.b, c.g, c.r, 0.0)) & 0xFFFFFFu);
entlayer[qi] = t;
} else entlayer[qi] = additive ? (0x01000000u | (t & 0xFFFFFFu)) : t;
}
}