init
This commit is contained in:
commit
87bff164f1
416 files changed
+279512
No files matched your search
@@ -0,0 +1,127 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
layout(local_size_x = 8, local_size_y = 8) in;
|
||||
#include "common.glsl"
|
||||
|
||||
// Material reactions (liquids mixing, acid, water on lava, ...). The grid is cut into disjoint pairs of neighbouring cells; pc.pass_
|
||||
// (0..3) selects the pairing: 0/1 horizontal pairs starting at even/odd columns, 2/3 vertical pairs. Both cells of a pair evaluate the
|
||||
// same reaction (symmetric hash) and each applies its own side, so no cell is written twice. Four passes visit every adjacency once per frame.
|
||||
layout(std430, set = 0, binding = 28) readonly buffer RHead { uint rhead[]; }; // [a * n + b] = (offset << 8) | count
|
||||
layout(std430, set = 0, binding = 23) buffer Ctrl { ivec4 inp; ivec4 inp2; ivec4 inp3; vec4 outp; vec4 outp2; vec4 view; vec4 hand0; ivec4 hand1; vec4 hand2; ivec4 burnN; ivec4 burnEv[256]; ivec4 reactN; ivec4 reactEv[64]; } ctrl; // reactEv: entities to spawn (x, y, entity index + 1)
|
||||
layout(std430, set = 0, binding = 29) readonly buffer RRec { uint rrec[]; }; // 5 words per entry: outs (a | b << 16, 0xFFFF = same), probability / 65536
|
||||
|
||||
void main() {
|
||||
ivec2 p = ivec2(gl_GlobalInvocationID.xy);
|
||||
if (p.x >= pc.gw || p.y >= pc.gh) return;
|
||||
int ph = pc.pass_ & 3;
|
||||
ivec2 q;
|
||||
if (ph < 2) q = p + ivec2(((p.x & 1) == ph) ? 1 : -1, 0);
|
||||
else q = p + ivec2(0, ((p.y & 1) == (ph - 2)) ? 1 : -1);
|
||||
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) return;
|
||||
int i = p.y * pc.gw + p.x, j = q.y * pc.gw + q.x;
|
||||
uint ci = cells[i], cj = cells[j];
|
||||
uint mi = cell_mat(ci), mj = cell_mat(cj);
|
||||
if (mi == 0u && mj == 0u) return;
|
||||
uint n = mats[mats.length() - 1u].w;
|
||||
uint h = rhead[mi * n + mj];
|
||||
uint cnt = h & 255u;
|
||||
if (cnt == 0u) return;
|
||||
uint lo = uint(min(i, j)), hi = uint(max(i, j));
|
||||
uint rr = hash3(lo, hi, uint(pc.frame * 4 + ph) ^ 0x51u);
|
||||
uint k = 0u; // the record of the pair table: R % count with the roll R that also gates the attempt (0070eaf0)
|
||||
// 0070eaf0: every cell that has a reaction threshold (CellData + 0x22c: the largest probability of a reaction it is the first input of; air is no cell and never starts one) tries once per
|
||||
// update with ONE random neighbour of four, rolls R (0..10000) against min(that threshold, the record's probability) and the record must accept the direction: the pair gets the chance of
|
||||
// each of its two cells separately (rec / 4 for a material next to air, not rec / 2).
|
||||
{
|
||||
const bool iLo = i < j;
|
||||
const uint mA = iLo ? mi : mj, mB = iLo ? mj : mi;
|
||||
const ivec2 pA = iLo ? p : q, pB = iLo ? q : p;
|
||||
const uint hA = rhead[mA * n + mB], hB = rhead[mB * n + mA];
|
||||
const uint eA = ((hA >> 8) + k % max(hA & 255u, 1u)) * 5u, eB = ((hB >> 8) + k % max(hB & 255u, 1u)) * 5u;
|
||||
const uint pwA = rrec[eA + 1u], pwB = rrec[eB + 1u];
|
||||
const ivec2 dAB = pB - pA;
|
||||
const uint relA = dAB.y < 0 ? 1u : dAB.y > 0 ? 2u : dAB.x < 0 ? 3u : 4u, relB = relA == 1u ? 2u : relA == 2u ? 1u : relA == 3u ? 4u : 3u;
|
||||
const uint dirA = (pwA >> 16) & 7u, dirB = (pwB >> 16) & 7u;
|
||||
// each cell has its own roll R = next15 % 10001: the material threshold (CellData + 0x22c, positive) and the record's threshold both accept R <= threshold, the record is R % count
|
||||
const uint RA = (hash(rr ^ 0xA2u) & 0x7FFFu) % 10001u, RB = (hash(rr ^ 0xB2u) & 0x7FFFu) % 10001u;
|
||||
const uint kA = RA % max(hA & 255u, 1u), kB = RB % max(hB & 255u, 1u);
|
||||
const uint eA2 = ((hA >> 8) + kA) * 5u, eB2 = ((hB >> 8) + kB) * 5u;
|
||||
const uint matA = rhead[n * n + mA], matB = rhead[n * n + mB];
|
||||
const bool fireA = mA != 0u && (hA & 255u) != 0u && matA > 0u && RA <= matA && RA <= (rrec[eA2 + 1u] & 0xFFFFu) && (((rrec[eA2 + 1u] >> 16) & 7u) == 0u || ((rrec[eA2 + 1u] >> 16) & 7u) == relA) && (hash(rr ^ 0xA1u) & 3u) == 0u;
|
||||
const bool fireB = mB != 0u && (hB & 255u) != 0u && matB > 0u && RB <= matB && RB <= (rrec[eB2 + 1u] & 0xFFFFu) && (((rrec[eB2 + 1u] >> 16) & 7u) == 0u || ((rrec[eB2 + 1u] >> 16) & 7u) == relB) && (hash(rr ^ 0xB1u) & 3u) == 0u;
|
||||
if (!fireA && !fireB) return;
|
||||
k = fireA ? kA : kB;
|
||||
}
|
||||
uint e = ((h >> 8) + k % cnt) * 5u;
|
||||
uint outs = rrec[e];
|
||||
uint third = rrec[e + 2u];
|
||||
uint blob = rrec[e + 3u];
|
||||
uint entityIdx = rrec[e + 4u] & 0x7FFFFFFFu;
|
||||
bool second = (mi == mj) && (i > j); // equal materials: the lower cell takes the first output
|
||||
uint o = second ? (outs >> 16) : (outs & 0xFFFFu);
|
||||
const bool firstIsI0 = (rrec[e + 4u] & 0x80000000u) == 0u; // (the record is the mirrored one when the first input is the second material of the pair)
|
||||
const uint reqLife = blob >> 20;
|
||||
if (reqLife > 0u && birth_age(birth[firstIsI0 ? i : j]) < reqLife) return; // req_lifetime: the first cell must be old enough
|
||||
if (((blob >> 19) & 1u) != 0u && firstIsI0 && !second) { // destroy_horizontally_lonely_pixels: the first output becomes air when both horizontal neighbours are empty (both probed)
|
||||
const bool le = p.x > 0 && cell_mat(cells[i - 1]) == 0u, ri = p.x + 1 < pc.gw && cell_mat(cells[i + 1]) == 0u;
|
||||
if (le && ri) o = 0u;
|
||||
}
|
||||
// three inputs (0070ebf0): a third cell next to the first input's cell (a cardinal neighbour chosen at random; the second cell's place is mirrored to the other side)
|
||||
// must hold the third material; the thread of the first cell writes its output
|
||||
if ((third & 0xFFFFu) != 0xFFFFu) {
|
||||
const bool firstIsI = firstIsI0;
|
||||
const ivec2 pf = firstIsI ? p : q, ps = firstIsI ? q : p;
|
||||
const ivec2 dirs[4] = ivec2[4](ivec2(0, -1), ivec2(-1, 0), ivec2(1, 0), ivec2(0, 1));
|
||||
ivec2 p3 = pf + dirs[(rr >> 20) & 3u];
|
||||
if (p3 == ps) p3 = 2 * pf - ps;
|
||||
if (p3.x < 0 || p3.y < 0 || p3.x >= pc.gw || p3.y >= pc.gh) return;
|
||||
const int k3 = p3.y * pc.gw + p3.x;
|
||||
const uint c3 = cells[k3];
|
||||
if (cell_mat(c3) != (third & 0xFFFFu)) return;
|
||||
const uint o3 = (third >> 16) & 0xFFFFu;
|
||||
if (firstIsI && o3 != 0xFFFFu && o3 != cell_mat(c3)) { atomicCompSwap(cells[k3], c3, o3 | (c3 & 0x00FF0000u)); birth[k3] = birth_frame(); }
|
||||
}
|
||||
if (o == 0xFFFFu || o == mi) return; // this side stays as it is
|
||||
cells[i] = o | (ci & 0x00FF0000u); // keeps the colour variation, clears burning and direction bits
|
||||
ext[i] = vec2(0.0);
|
||||
birth[i] = birth_frame();
|
||||
if (entityIdx != 0u && firstIsI0 && !second) { // the reaction loads an entity at the position of the first input (the host spawns it)
|
||||
const int ei = atomicAdd(ctrl.reactN.x, 1);
|
||||
if (ei < 64) ctrl.reactEv[ei] = ivec4(p.x + pc.view_x, p.y + pc.view_y, int(entityIdx), 0);
|
||||
else atomicAdd(ctrl.reactN.x, -1);
|
||||
}
|
||||
// blob_radius with blob_restrict_to_input_material (0071ab50 conditional mode): trunc(r * 2 pi + 0.5) rays of unit steps from the cell; a cell of the input material converts,
|
||||
// one that already holds the output lets the ray go on, anything else ends it (a flood of the connected input material up to the radius)
|
||||
{
|
||||
const uint rad = second ? ((blob >> 8) & 255u) : (blob & 255u);
|
||||
const bool restricted = ((blob >> (second ? 17 : 16)) & 1u) != 0u;
|
||||
if (rad > 0u && restricted) {
|
||||
const int nr = int(float(rad) * 6.2831853 + 0.5);
|
||||
for (int ray = 0; ray < nr; ++ray) {
|
||||
const float a = float(ray) * 6.2831853 / float(nr);
|
||||
const vec2 dir = vec2(cos(a), sin(a));
|
||||
for (int st = 1; st <= int(rad); ++st) {
|
||||
const ivec2 t = p + ivec2(trunc(dir * float(st)));
|
||||
if (t.x < 0 || t.y < 0 || t.x >= pc.gw || t.y >= pc.gh) break;
|
||||
const int ti = t.y * pc.gw + t.x;
|
||||
const uint tc = cells[ti], tm = cell_mat(tc);
|
||||
if (tm == o) continue;
|
||||
if (tm != mi) break;
|
||||
if (atomicCompSwap(cells[ti], tc, o | (tc & 0x00FF0000u)) == tc) { ext[ti] = vec2(0.0); birth[ti] = birth_frame(); } // a converted cell starts afresh (0070d0b0)
|
||||
}
|
||||
}
|
||||
} else if (rad > 0u) { // direct mode (0071ab50, restriction explicitly off): every loaded cell of the disk dx^2 + dy^2 < r^2 takes the output, whatever it holds
|
||||
const int ri = int(rad);
|
||||
for (int dy = -ri; dy <= ri; ++dy)
|
||||
for (int dx = -ri; dx <= ri; ++dx) {
|
||||
if (dx * dx + dy * dy >= ri * ri) continue;
|
||||
const ivec2 t = p + ivec2(dx, dy);
|
||||
if (t.x < 0 || t.y < 0 || t.x >= pc.gw || t.y >= pc.gh) continue;
|
||||
const int ti = t.y * pc.gw + t.x;
|
||||
const uint tc = cells[ti];
|
||||
if (cell_mat(tc) == o) continue;
|
||||
if (atomicCompSwap(cells[ti], tc, o | (tc & 0x00FF0000u)) == tc) { ext[ti] = vec2(0.0); birth[ti] = birth_frame(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user