// 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) }