init
This commit is contained in:
commit
87bff164f1
416 files changed
+279512
No files matched your search
@@ -0,0 +1,90 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
layout(local_size_x = 64) in;
|
||||
#include "rigid_common.glsl"
|
||||
|
||||
// Rigid bodies displace liquids: the liquid cells inside their volume are moved to the nearest free cell outside it, away from the centre (preferring upward).
|
||||
// (One workgroup per entity, which return at once, then one per rigid body.)
|
||||
layout(std430, set = 0, binding = 23) readonly buffer Ctrl { ivec4 inp; } ctrl;
|
||||
|
||||
// Liquids, and for bodies that do not go through sand (CellData solid_go_through_sand, bit 9 of the body flags) the powders too: a body that sinks into a pile pushes the grains out.
|
||||
bool liquid_cell(uint c, bool powders) {
|
||||
uint m = cell_mat(c);
|
||||
if (m == 0u) return false;
|
||||
uint f = mflags(m);
|
||||
if ((f & F_STATIC) != 0u) return false;
|
||||
return (f & F_LIQUID) != 0u && ((f & F_SAND) == 0u || powders);
|
||||
}
|
||||
|
||||
// Moves the cell at world position w out of the volume: the volume is a box (bodyIdx < 0) or a rigid body's mask.
|
||||
void push_out(ivec2 w, vec2 centre, ivec4 box, int bodyIdx) {
|
||||
const bool powders = bodyIdx >= 0 && (bodies[bodyIdx].i.z & 512) == 0;
|
||||
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;
|
||||
int i = p.y * pc.gw + p.x;
|
||||
uint c = cells[i];
|
||||
if (!liquid_cell(c, powders)) return;
|
||||
vec2 d = vec2(w) + 0.5 - centre;
|
||||
d.y -= 0.8; // up is preferred
|
||||
d = length(d) < 0.01 ? vec2(0.0, -1.0) : normalize(d);
|
||||
// the target is claimed first (only free cells are claimed), then the source is released; another invocation that already moved the source (bodies that overlap handle the
|
||||
// same cell) makes this one give its target back. Nothing is lost or doubled: before, the source was emptied first and put back when no free cell was found, and a neighbour
|
||||
// could fill the briefly empty source in between (a full pool with rubble in it lost its water)
|
||||
const vec2 e = ext[i];
|
||||
for (int r = 1; r <= 12; ++r) {
|
||||
ivec2 t = w + ivec2(round(d * float(r)));
|
||||
ivec2 q = t - ivec2(pc.view_x, pc.view_y);
|
||||
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) break;
|
||||
bool inside;
|
||||
if (bodyIdx < 0) inside = t.x >= box.x && t.x < box.z && t.y >= box.y && t.y < box.w;
|
||||
else {
|
||||
Body b = bodies[bodyIdx];
|
||||
int s = b.i.x;
|
||||
vec2 dd = vec2(t) + 0.5 - b.p.xy;
|
||||
float cs = cos(b.p.z), sn = sin(b.p.z);
|
||||
vec2 im = vec2(cs * dd.x + sn * dd.y, -sn * dd.x + cs * dd.y) + vec2(shf(s, 5), shf(s, 6));
|
||||
inside = shape_solid(s, int(floor(im.x)), int(floor(im.y)));
|
||||
}
|
||||
if (inside) continue;
|
||||
int ti = q.y * pc.gw + q.x;
|
||||
if (atomicCompSwap(cells[ti], 0u, c) == 0u) { // a free target, now holding the liquid
|
||||
if (atomicCompSwap(cells[i], c, 0u) == c) { ext[ti] = e; ext[i] = vec2(0.0); }
|
||||
else atomicCompSwap(cells[ti], c, 0u); // the source went elsewhere meanwhile: give the target back
|
||||
return;
|
||||
}
|
||||
}
|
||||
// nowhere to go: the liquid stays where it is
|
||||
}
|
||||
|
||||
void main() {
|
||||
int g = int(gl_WorkGroupID.x), t = int(gl_LocalInvocationID.x);
|
||||
int nEnt = ctrl.inp.w;
|
||||
if (g < nEnt) {
|
||||
return; // creatures and the player displace through the particle path of entities.comp (docs/DISPLACEMENT_AND_FIRE.md); only rigid bodies are pushed out here (the engine's body rule is not recovered)
|
||||
Ent e = ents[g];
|
||||
int kind = e.st.x;
|
||||
if ((kind != 1 && kind != 2 && kind != 3) || (e.st.w & 8) != 0) return;
|
||||
ivec2 ip = ivec2(floor(e.a.xy));
|
||||
ivec2 lo = ip + ivec2(int(e.box.x), int(e.box.z)), hi = ip + ivec2(int(e.box.y), int(e.box.w));
|
||||
ivec2 sz = hi - lo;
|
||||
if (sz.x <= 0 || sz.y <= 0 || sz.x * sz.y > 4096) return;
|
||||
vec2 centre = vec2(lo + hi) * 0.5;
|
||||
for (int k = t; k < sz.x * sz.y; k += 64) push_out(lo + ivec2(k % sz.x, k / sz.x), centre, ivec4(lo, hi), -1);
|
||||
} else {
|
||||
int bi = g - nEnt;
|
||||
if (bi >= bhdr.x) return;
|
||||
Body b = bodies[bi];
|
||||
if ((b.i.z & 2) != 0) return;
|
||||
int s = b.i.x;
|
||||
float rad = shf(s, 9);
|
||||
int n = int(2.0 * rad) + 2;
|
||||
ivec2 lo = ivec2(floor(b.p.xy - vec2(rad)));
|
||||
for (int k = t; k < n * n; k += 64) {
|
||||
ivec2 w = lo + ivec2(k % n, k / n);
|
||||
vec2 dd = vec2(w) + 0.5 - b.p.xy;
|
||||
float cs = cos(b.p.z), sn = sin(b.p.z);
|
||||
vec2 im = vec2(cs * dd.x + sn * dd.y, -sn * dd.x + cs * dd.y) + vec2(shf(s, 5), shf(s, 6));
|
||||
if (shape_solid(s, int(floor(im.x)), int(floor(im.y)))) push_out(w, b.p.xy, ivec4(0), bi);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user