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

+71
View File
@@ -0,0 +1,71 @@
// Shared declarations of the GPU rigid-body engine (rigid_solve.comp, rigid_commit.comp, rigid_frame.comp).
// The engine is the GPU port of src/physics/rigid.cpp: bodies are pixel masks, terrain is the live cell grid, contacts are aggregated
// into one manifold per pair and resolved with impulses. Bodies are solved Jacobi-style: every body reads the state of the others
// from the previous sub-step (`bodies`) and writes its own result to `bnext`; rigid_commit copies bnext back.
#include "common.glsl"
struct Ent {
vec4 a, box, mv, ai;
ivec4 st;
vec4 hp;
ivec4 x, rg, rg2, aux;
vec4 ex; // detection cone (cos of half angle), eye offset y, melee enabled, 0
vec4 ex2; // ranged attack: projectile speed, gravity
ivec4 ex3; // blood material + 1, blood colour, damage types taken since the last check (bit 1 projectile, 2 explosion, 4 fire, 8 melee), 0
vec4 ex4; // air in the lungs (frames), air maximum (0 = does not need air), damage per frame without air, frames left on fire
vec4 ex5; // swimming: swim_idle_buoyancy_coeff, swim_up_buoyancy_coeff, swim_drag, swim_extra_horizontal_drag
vec4 ex6; // swim_down_buoyancy_coeff, frames not swimming, pixel of the last liquid count (x, y)
vec4 ex7; // blood_multiplier (creatures); liquid inventory of a body: reserve, material + 1, frames of emission left
ivec4 ex8; vec4 ex9; vec4 ex10; vec4 ex11; vec4 ex12, ex13, ex14, ex15, ex16, ex17, ex18, ex19; // damage event of a body: hit point relative to the body x 1000, damage x 1000 pending
};
layout(std430, set = 0, binding = 22) buffer Ents { Ent ents[]; };
// shape table: 16 words per shape (w, h, mask offset, sample offset, sample count, com x, com y, mass, inertia, radius as float bits),
// followed by the pixel masks (one word per pixel) and the outline samples (two float words each).
layout(std430, set = 0, binding = 30) readonly buffer Shapes { uint sh[]; };
struct Body {
vec4 p; // centre of mass x, y, angle, angular velocity
vec4 v; // velocity x, y, restitution, friction
ivec4 i; // shape, entity slot, flags (1 asleep, 2 removed), quiet frames
vec4 q; // anchor x, y (the entity origin in image coordinates), density, probe counter
vec4 l; // x, y, angle at the last sleep check
vec4 n; // fragile: impact speed (cells per frame) above which it is damaged, 0 = unbreakable / nail point relative to the entity origin (x, y) / radius in which a surface holds the nail; flag B_NAILED
vec4 m; // collision group (bodies of one group do not collide), y = 1: passable for creatures and projectiles (corpses)
ivec4 jn; // joint partners (body indices, -1 = none)
vec4 ja0, ja1, ja2, ja3; // joint anchors (x, y on this body, x, y on the partner), relative to the centres of mass, in the bodies' own frames
vec4 jb; // break_force multiplier of each joint slot (0 = the joint does not break from force); l.w is the multiplier of the nail
vec4 d; // component values: buoyancy, linear damping, angular damping
};
layout(std430, set = 0, binding = 31) buffer Bodies { ivec4 bhdr; Body bodies[]; }; // bhdr.x = body count
layout(std430, set = 0, binding = 32) buffer BNext { ivec4 nhdr; Body bnext[]; };
const int B_ASLEEP = 1, B_REMOVED = 2, B_NAILED = 4; // nailed: hangs on the wall until the cells around the nail are gone
int shi(int s, int k) { return int(sh[s * 16 + k]); }
float shf(int s, int k) { return uintBitsToFloat(sh[s * 16 + k]); }
bool shape_solid(int s, int x, int y) {
int w = shi(s, 0), h = shi(s, 1);
return x >= 0 && y >= 0 && x < w && y < h && sh[shi(s, 2) + y * w + x] != 0u;
}
vec2 sample_of(int s, int k) {
int o = shi(s, 3) + 2 * k;
return vec2(uintBitsToFloat(sh[o]), uintBitsToFloat(sh[o + 1]));
}
vec2 rot2(float c, float s, vec2 v) { return vec2(c * v.x - s * v.y, s * v.x + c * v.y); }
bool solid_at(ivec2 w) {
ivec2 p = w - ivec2(pc.view_x, pc.view_y);
if (p.x < 0 || p.y < 0 || p.x >= pc.gw || p.y >= pc.gh) return false; // no ground outside the window: bodies there are frozen
uint m = cell_mat(cells[p.y * pc.gw + p.x]);
if (m == 0u) return false;
return (mflags(m) & (F_STATIC | F_SAND)) != 0u;
}
bool liquid_at(ivec2 w) {
ivec2 p = w - ivec2(pc.view_x, pc.view_y);
if (p.x < 0 || p.y < 0 || p.x >= pc.gw || p.y >= pc.gh) return false;
uint m = cell_mat(cells[p.y * pc.gw + p.x]);
if (m == 0u) return false;
uint f = mflags(m);
return (f & F_LIQCELL) != 0u && (f & F_POWDER) == 0u; // liquid and not powder (a static liquid counts too)
}