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

+53
View File
@@ -0,0 +1,53 @@
#version 450
#extension GL_GOOGLE_include_directive : require
layout(local_size_x = 64) in;
#include "rigid_common.glsl"
// Explosions (from projectiles on the GPU, from props on the host) push the rigid bodies and wake them.
layout(std430, set = 0, binding = 37) buffer Xev { ivec4 xhead; vec4 xe[512]; };
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;
float mass = shf(s, 7), radius = shf(s, 9);
bool touched = false;
for (int k = 0; k < min(xhead.x, 512); ++k) {
vec4 e = xe[k]; // x, y, radius, power
if (e.w < -0.5) { // an explosion with the force of 00657960: this entry and the next one (force min, force max)
vec4 f2 = xe[min(k + 1, 511)];
++k;
const float pixels = float(shi(s, 4) > 0 ? int(shf(s, 7)) : 1);
const float massKg = max(pixels * B.q.z * 0.01, 1.0e-4);
vec2 O = e.xy, C = B.p.xy;
float dist = length(C - O) * 0.1, Ru = e.z * 0.1; // physics units (10 pixels each)
if (dist > Ru) continue;
// the original needs the angular bin of the explosion to reach this body: approximated by a line of sight through the grid that no solid cell interrupts
bool blocked = false;
const int steps = int(dist * 10.0);
for (int q = 1; q < steps && !blocked; ++q) blocked = solid_at(ivec2(floor(mix(O, C, float(q) / float(steps)))));
if (blocked) continue;
float t = Ru == 0.0 ? 1.0 : 1.0 - dist / Ru;
float A = (f2.y - f2.x) * t + f2.x;
vec2 n = dist >= 1.19e-7 ? normalize(C - O) : vec2(0.0);
// F = n A (x mass if the body weighs less than 1), x 360 N, dv = F / m / 360 per frame in pixels: = n A min(1, m) / m
B.v.xy += n * A * min(1.0, massKg) / massKg;
const float inertiaKg = max(shf(s, 8) * B.q.z * 1.0e-4, 1.0e-6);
const float tau = float(hash3(bi, uint(xhead.x), 91u) & 0x7FFFu) / 32767.0 * 30.0 - 15.0; // the random torque of the original
B.p.w += tau / (3600.0 * inertiaKg);
touched = true;
continue;
}
vec2 d = B.p.xy - e.xy - vec2(0.0, 2.0);
float dist = length(d);
if (dist > e.z + radius) continue;
float f = e.w * max(0.0, 1.0 - dist / (e.z + radius)) / sqrt(max(1.0, mass * B.q.z) / 20.0);
vec2 n = dist > 1e-3 ? d / dist : vec2(0.0, -1.0);
B.v.xy += n * f;
B.p.w += (n.x > 0.0 ? 1.0 : -1.0) * f * 0.05;
touched = true;
}
if (touched) { B.i.z &= ~B_ASLEEP; B.i.w = 0; bodies[bi] = B; }
}