Files
2026-10-19 20:59:15 +02:00

68 lines
3.1 KiB
Plaintext

#version 450
#extension GL_GOOGLE_include_directive : require
layout(local_size_x = 64) in;
#include "rigid_common.glsl"
// Once per frame: sleeping (resting bodies stop being simulated, sleeping ones re-check their support), and the entity's position and angle.
layout(std430, set = 0, binding = 27) buffer Edits { ivec4 ehead; vec4 ee[512]; }; // cell edits: the flames of a burning corpse
void main() {
uint bi = gl_GlobalInvocationID.x;
if (int(bi) >= bhdr.x) return;
Body B = bodies[bi];
if ((B.i.z & B_REMOVED) != 0) return;
int s = B.i.x;
int nS = shi(s, 4);
vec2 com = vec2(shf(s, 5), shf(s, 6));
float c = cos(B.p.z), sn = sin(B.p.z);
if ((B.i.z & 8) != 0) {
// simulated on the CPU (src/phys): the sleep state comes from there
} else if ((B.i.z & B_ASLEEP) != 0) {
B.q.w += 1.0;
if (B.q.w >= 12.0) { // re-check the support now and then
B.q.w = 0.0;
bool supported = false;
for (int k = 0; k < nS && !supported; ++k) {
vec2 r = rot2(c, sn, sample_of(s, k));
supported = solid_at(ivec2(floor(B.p.x + r.x), floor(B.p.y + r.y + 1.5)));
}
if (!supported) { B.i.z &= ~B_ASLEEP; B.i.w = 0; }
}
} else {
// 009be020: the sleep timer counts while the velocity stays under the tolerances (0.01 units per second linear, 2 degrees per second angular; pixels per frame at scale 10); a body
// sleeps when it has been quiet for half a second AND every body joined to it has too (the island's minimum timer)
const bool quiet = length(B.v.xy) < 0.01 * 10.0 / 60.0 && abs(B.p.w) < 0.034906585 / 60.0;
B.i.w = quiet ? B.i.w + 1 : 0;
if (B.i.w >= 30) {
bool island = true;
for (int k = 0; k < 4 && island; ++k) {
const int j = B.jn[k];
if (j < 0) continue;
const Body C = bodies[j];
if ((C.i.z & B_REMOVED) != 0 || (C.i.z & B_ASLEEP) != 0) continue;
island = C.i.w >= 30;
}
if (island) { B.i.z |= B_ASLEEP; B.v.xy = vec2(0.0); B.p.w = 0.0; B.i.w = 0; }
}
B.l = vec4(B.p.xy, B.p.z, 0.0);
}
if (B.m.z > 0.0) { // a burning corpse part: flames now and then, water puts it out (the pixels of burnable props burn in rigid_burn.comp)
B.m.z -= 1.0;
ivec2 cc = ivec2(floor(B.p.xy)) - ivec2(pc.view_x, pc.view_y);
if (cc.x >= 0 && cc.y >= 0 && cc.x < pc.gw && cc.y < pc.gh) {
uint cm = cell_mat(cells[cc.y * pc.gw + cc.x]);
if (cm != 0u && ((mats[3u * cm + 2u].z >> 18) & 1u) != 0u) B.m.z = 0.0;
}
if (B.m.z > 0.0 && (hash3(bi, uint(pc.frame), 17u) & 3u) == 0u) {
uint ei = uint(atomicAdd(ehead.x, 1));
vec2 fp = B.p.xy + vec2(0.0, -1.0);
if (ei < 256u) { ee[2u * ei] = vec4(fp, 1.5, 0.0); ee[2u * ei + 1u] = vec4(1.0, float(mats[mats.length() - 1u].x), 0.45, 0.0); }
}
}
bodies[bi] = B;
if (B.i.y >= 0) {
vec2 d = rot2(c, sn, B.q.xy - com);
ents[B.i.y].a = vec4(B.p.xy + d, B.p.z, 0.0);
}
}