init
This commit is contained in:
commit
87bff164f1
416 files changed
+279512
No files matched your search
@@ -0,0 +1,123 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
layout(local_size_x = 256) in;
|
||||
#include "rigid_common.glsl"
|
||||
|
||||
// Fire inside the rigid bodies of a burnable material (docs/FIRE_FRACTURE_AND_LIQUIDS.md, DISPLACEMENT_AND_FIRE.md, CEILING_ATTACHMENT_AND_CONTACT_GEOMETRY.md).
|
||||
// One workgroup per body, a thread per group of pixels. A pixel has a state word in `burn`: bit 31 burning, bit 30 burnt away (reported to the host, which removes it from
|
||||
// the body and splits it), bits 16-23 fade, bits 0-15 the burn age. A burning pixel does what a burning solid cell does:
|
||||
// * common burning (0070fb10): flames into (x-1..x+1, y-1) with generates_flames percent, smoke, requires_oxygen fade (restored by an accepted flame, else -1 per update,
|
||||
// burning stops below 1), and one spread attempt: r % 101 <= fade, then ONE of the four neighbours, then the ignition draw r % 101 < 100 - autoignition_temperature;
|
||||
// * then the age grows, and on every 32nd frame a pixel with fire_hp != -1 and age > fire_hp is removed.
|
||||
// A pixel that is not burning catches fire from the fire sources in its cell and the four around it with the probabilities of burn.comp. Water puts it out.
|
||||
layout(std430, set = 0, binding = 41) buffer Burn { uint burn[]; };
|
||||
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]; } ctrl;
|
||||
|
||||
const uint BURNING = 0x80000000u, BURNT = 0x40000000u;
|
||||
|
||||
float rnd(uint a, uint b, uint c) { return float(hash3(a, b, c) & 0xFFFFu) / 65536.0; }
|
||||
layout(std430, set = 0, binding = 8) readonly buffer Tables { uint tbl[]; }; // 1024 noise words, 4 per material (burning explosion), then 2 per material: flame and smoke material + 1
|
||||
uint flame_material(uint m, uint dflt) { const uint v = tbl[1024u + 4u * mats[mats.length() - 1u].w + 2u * m]; return v != 0u ? v - 1u : dflt; }
|
||||
uint smoke_material(uint m, uint dflt) { const uint v = tbl[1024u + 4u * mats[mats.length() - 1u].w + 2u * m + 1u]; return v != 0u ? v - 1u : dflt; }
|
||||
|
||||
void main() {
|
||||
int bi = int(gl_WorkGroupID.x);
|
||||
if (bi >= bhdr.x) return;
|
||||
Body B = bodies[bi];
|
||||
if ((B.i.z & B_REMOVED) != 0 || B.i.y < 0) return;
|
||||
const uint matp1 = uint(ents[B.i.y].ex5.z + 0.5);
|
||||
if (matp1 == 0u) return;
|
||||
const uint m = matp1 - 1u;
|
||||
const uint mz = mats[3u * m + 2u].z, mw = mats[3u * m + 2u].w;
|
||||
const int s = B.i.x;
|
||||
const int w = shi(s, 0), h = shi(s, 1);
|
||||
if (w * h > 4096) return;
|
||||
const vec2 com = vec2(shf(s, 5), shf(s, 6));
|
||||
const float cs = cos(B.p.z), sn = sin(B.p.z);
|
||||
const uvec4 sp = mats[mats.length() - 1u]; // fire, smoke, steam, count
|
||||
const int ai = int(mw & 255u), tempFire = int((mw >> 8) & 255u), smokeP = int((mw >> 16) & 255u), flameP = int((mw >> 24) & 255u);
|
||||
const int fireHp = int(mz << 16) >> 16; // signed 16 bits
|
||||
const bool noBurnOut = fireHp == -1;
|
||||
const bool needO2 = ((mz >> 19) & 1u) != 0u;
|
||||
const float pIgnite = max(0.0, float(100 - ai)) / 101.0;
|
||||
const uint base = uint(bi) * 4096u;
|
||||
for (int px = int(gl_LocalInvocationID.x); px < w * h; px += 256) {
|
||||
const ivec2 pp = ivec2(px % w, px / w);
|
||||
if (!shape_solid(s, pp.x, pp.y)) continue;
|
||||
uint st = burn[base + uint(px)];
|
||||
if ((st & BURNT) != 0u) continue;
|
||||
const vec2 wp = B.p.xy + rot2(cs, sn, vec2(pp) + 0.5 - com);
|
||||
const ivec2 wc = ivec2(floor(wp));
|
||||
const uint seed = uint(bi) * 4099u + uint(px);
|
||||
if ((st & BURNING) == 0u) {
|
||||
// fire sources in the pixel's cell and the four around it (cells are free under a body)
|
||||
float keep = 1.0, bestFade = -1.0;
|
||||
bool wet = false;
|
||||
for (int d = 0; d < 5; ++d) {
|
||||
const ivec2 q = wc + ivec2(d == 1 ? 1 : d == 2 ? -1 : 0, d == 3 ? 1 : d == 4 ? -1 : 0) - ivec2(pc.view_x, pc.view_y);
|
||||
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) continue;
|
||||
const uint cw = cells[q.y * pc.gw + q.x], cm = cell_mat(cw);
|
||||
if (cm == 0u) continue;
|
||||
const uint nz = mats[3u * cm + 2u].z, nw = mats[3u * cm + 2u].w;
|
||||
if (((nz >> 18) & 1u) != 0u) wet = true;
|
||||
const bool nBurning = (cw & BURN_BIT) != 0u;
|
||||
if (!(nBurning || ((nz >> 17) & 1u) != 0u)) continue;
|
||||
int nfi = fade_of(birth[q.y * pc.gw + q.x]);
|
||||
if (!nBurning && nfi == 0) nfi = int((nw >> 8) & 255u);
|
||||
const float nf = float(nfi);
|
||||
const float gate = nfi < 0 ? 0.0 : min(nf + 1.0, 101.0) / 101.0;
|
||||
float pSrc = gate * 0.25 * pIgnite;
|
||||
if ((mflags(cm) & F_FIRE) != 0u) pSrc = 1.0 - (1.0 - pSrc) * (1.0 - pSrc); // a fire cell attempts twice
|
||||
keep *= 1.0 - min(pSrc, 1.0);
|
||||
if (rnd(seed, uint(pc.frame), 20u + uint(d)) < pSrc && bestFade < 0.0) bestFade = nf; // the fade of the source that ignited it
|
||||
}
|
||||
if (!wet && bestFade >= 0.0 && rnd(seed, uint(pc.frame), 1u) > keep) burn[base + uint(px)] = BURNING | (uint(min(bestFade, 255.0)) << 16) | (st & 0xFFFFu);
|
||||
continue;
|
||||
}
|
||||
// burning
|
||||
uint age = st & 0xFFFFu;
|
||||
int fade = int((st >> 16) & 255u);
|
||||
bool wet = false;
|
||||
for (int d = 0; d < 5 && !wet; ++d) {
|
||||
const ivec2 q = wc + ivec2(d == 1 ? 1 : d == 2 ? -1 : 0, d == 3 ? 1 : d == 4 ? -1 : 0) - ivec2(pc.view_x, pc.view_y);
|
||||
if (q.x < 0 || q.y < 0 || q.x >= pc.gw || q.y >= pc.gh) continue;
|
||||
const uint cm = cell_mat(cells[q.y * pc.gw + q.x]);
|
||||
wet = cm != 0u && ((mats[3u * cm + 2u].z >> 18) & 1u) != 0u;
|
||||
}
|
||||
if (wet) { burn[base + uint(px)] = age; continue; }
|
||||
bool flameAccepted = false;
|
||||
if (flameP > 0 && int(rnd(seed, uint(pc.frame), 2u) * 101.0) < flameP) {
|
||||
const ivec2 t = wc + ivec2(int(rnd(seed, uint(pc.frame), 3u) * 3.0) - 1, -1) - ivec2(pc.view_x, pc.view_y);
|
||||
if (t.x >= 0 && t.y >= 0 && t.x < pc.gw && t.y < pc.gh) {
|
||||
const int ti = t.y * pc.gw + t.x;
|
||||
const uint cur = cells[ti];
|
||||
if (cell_mat(cur) == 0u) { // an empty place (the word may hold a leftover colour variation): the flame takes it
|
||||
flameAccepted = atomicCompSwap(cells[ti], cur, flame_material(m, sp.x) | (hash3(seed, uint(pc.frame), 4u) & 0xFF0000u)) == cur;
|
||||
if (flameAccepted) birth[ti] = with_fade(birth_frame(), int((mats[3u * flame_material(m, sp.x) + 2u].w >> 8) & 255u)); // (0070f8c0: a new flame has its material's own fade, temperature_of_fire; the intensity is a separate field)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needO2) fade = flameAccepted ? tempFire : fade - 1;
|
||||
if (smokeP > 0 && int(rnd(seed, uint(pc.frame), 6u) * 101.0) < smokeP) {
|
||||
const ivec2 t = wc + ivec2(int(rnd(seed, uint(pc.frame), 7u) * 3.0) - 1, -1) - ivec2(pc.view_x, pc.view_y);
|
||||
if (t.x >= 0 && t.y >= 0 && t.x < pc.gw && t.y < pc.gh) atomicCompSwap(cells[t.y * pc.gw + t.x], 0u, smoke_material(m, sp.y) | (hash3(seed, uint(pc.frame), 8u) & 0xFF0000u));
|
||||
}
|
||||
if (fade < 1) { burn[base + uint(px)] = age; continue; } // out of oxygen: the pixel stops burning
|
||||
// one spread attempt towards one of the four neighbours inside the body
|
||||
if (int(hash3(seed, uint(pc.frame), 9u) % 101u) <= fade) {
|
||||
const uint dsel = hash3(seed, uint(pc.frame), 10u) & 3u;
|
||||
const ivec2 np = pp + (dsel == 0u ? ivec2(0, -1) : dsel == 1u ? ivec2(-1, 0) : dsel == 2u ? ivec2(1, 0) : ivec2(0, 1));
|
||||
if (shape_solid(s, np.x, np.y) && int(hash3(seed, uint(pc.frame), 11u) % 101u) < 100 - ai) {
|
||||
const uint ni = base + uint(np.y * w + np.x), old = burn[ni];
|
||||
if ((old & (BURNING | BURNT)) == 0u) atomicCompSwap(burn[ni], old, BURNING | (uint(fade) << 16) | (old & 0xFFFFu));
|
||||
}
|
||||
}
|
||||
age = (age + 1u) & 0xFFFFu; // 0070e060: a wrapping 16-bit age
|
||||
if ((pc.frame & 31) == 0 && !noBurnOut && fireHp < int(age)) {
|
||||
const int ei = atomicAdd(ctrl.burnN.x, 1);
|
||||
if (ei < 256) { ctrl.burnEv[ei] = ivec4(bi, px, 0, 0); burn[base + uint(px)] = BURNT | age; continue; }
|
||||
atomicAdd(ctrl.burnN.x, -1);
|
||||
}
|
||||
burn[base + uint(px)] = BURNING | (uint(fade) << 16) | age;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user