Files
Gaël 9bb9797271 Adding patch notes from git, UI, and loading files from the main install path properly.
Also fixed:
* flying wands not pathing properly.
* Lantern particles offset
* Wand fire offset
* Water spray from flask
2026-10-22 14:18:49 +02:00

46 lines
3.9 KiB
Plaintext

#version 450
#extension GL_GOOGLE_include_directive : require
layout(local_size_x = 64) in;
#include "fx_common.glsl"
// Particles requested by the host (effects of the rigid bodies: the splash of a body that hits something, ...): count, then per request (position, velocity), (life, gravity),
// (colour bits, mode, material). Mode 0: a cosmetic droplet that ends at the first cell it meets, stains it and leaves a cell of `material`, mode 2: the same without the cell (stains only), mode 1: a real particle of the material.
struct PartReq { vec4 a; vec4 b; uvec4 c; };
layout(std430, set = 0, binding = 51) buffer PartReqBuf { uvec4 rhead; PartReq reqs[]; };
void main() {
const uint i = gl_GlobalInvocationID.x;
if (i >= min(rhead.x, 1024u)) return;
const PartReq r = reqs[i];
if (r.c.y == 0u) emit_particle_hit(r.a.xy, r.a.zw, r.b.x, r.b.y, r.c.x, int(r.c.z));
else if (r.c.y == 2u) { const uint ps = emit_particle_hit(r.a.xy, r.a.zw, r.b.x, r.b.y, r.c.x, int(r.c.z)); if (ps != 0xFFFFFFFFu) fparts[ps].c.w = 1u; } // stains only, leaves no cell
else if (r.c.y == 3u) emit_particle(r.a.xy, r.a.zw, r.b.x, 0.0, r.c.x, true, true); // a light ray (SpriteParticleEmitterComponent, additive): fades, no cell
else if (r.c.y == 4u) { if ((r.c.w & 2u) == 0u || cell_free_at(r.a.xy)) {
// c.w bit 2: a glowing material (gfx_glow): additive, the colour scaled by the material's alpha; else bits 8-15 = 255 - alpha, the opacity
const bool glow = (r.c.w & 4u) != 0u;
const float al = 1.0 - float((r.c.w >> 8) & 0xFFu) / 255.0;
const uint rgb = glow ? ((uint(float((r.c.x >> 16) & 0xFFu) * al + 0.5) << 16) | (uint(float((r.c.x >> 8) & 0xFFu) * al + 0.5) << 8) | uint(float(r.c.x & 0xFFu) * al + 0.5)) : r.c.x;
const int ps = emit_particle_g(r.a.xy, r.a.zw, r.b.x, r.b.y, rgb, (r.c.w & 8u) == 0u, glow, (r.c.w & 1u) == 0u); // c.w bit 3: fade_based_on_lifetime 0
if (ps >= 0 && !glow) fparts[ps].c.z = (r.c.w >> 8) & 0xFFu;
if (ps >= 0 && r.b.z > 0.0) fparts[ps].c.w |= (min(uint(r.b.z * 1000.0 + 0.5), 4095u) << 20) | (min(uint(r.b.w * 4096.0 + 0.5), 4095u) << 8); // airflow_force (b.z), airflow_scale (b.w)
} } // a cosmetic particle (ParticleEmitterComponent emit_cosmetic_particles): fades, no cell; c.w bit 0: collide_with_grid 0, bit 1: cosmetic_force_create 0
else if (r.c.y == 5u) { // create_real_particles: the cell itself, in the empty cell (or over a gas / liquid unless only-if-space: c.w bit 1)
const ivec2 q = ivec2(floor(r.a.xy)) - ivec2(pc.view_x, pc.view_y);
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) return;
const int ci = q.y * pc.gw + q.x;
const uint nc = r.c.z | (((hash3(uint(ci), uint(pc.frame), 63u) >> 16) & 0xFFu) << 16);
const uint old = atomicCompSwap(cells[ci], 0u, nc);
if (old == 0u) { ext[ci] = vec2(0.0); birth[ci] = birth_frame(); }
else if ((r.c.w & 2u) == 0u && (mflags(cell_mat(old)) & (F_GAS | F_LIQUID)) != 0u && (mflags(cell_mat(old)) & (F_STATIC | F_SAND)) == 0u && atomicCompSwap(cells[ci], old, nc) == old) { ext[ci] = vec2(0.0); birth[ci] = birth_frame(); }
}
else if (r.c.y == 7u) { // PotionSystem 00bfdd10: mode 1, density zero, 20-cell penetration budget.
const int ps = alloc_part();
if (ps < 0) return;
fparts[ps].a = r.a;
fparts[ps].b = vec4(r.b.x, 1.0, uintBitsToFloat(birth_frame()), 0.0);
fparts[ps].c = uvec4(r.c.z | (((hash3(i, uint(pc.frame), 64u) >> 16) & 0xFFu) << 16), 1u, 20u, 0x300000u);
}
else if (r.c.y == 6u) emit_displaced(r.a.xy, r.a.zw, r.c.z | (((hash3(i, uint(pc.frame), 64u) >> 16) & 0xFFu) << 16), 2u, birth_frame()); // GameCreateParticle (007b3120 -> 00716af0): a cell of the material handed to the particle system like a displaced one (AddAsParticle 007168c0): it falls and goes back into the grid, waiting for a free place
else emit_material_particle(r.a.xy, r.a.zw, r.b.x, r.b.y, r.c.x, int(r.c.z));
}