* Adding clipper to generate the terrain's negative powder-contour offset. * Fixing RDB issues (fracture, active trigger, performances) * Fixing blood emission * Fixing the freezing formula on liquids * Fixing Steve spawning due to a missed test. * Reaction table properly build
105 lines
6.5 KiB
GLSL
105 lines
6.5 KiB
GLSL
// Shared by intent/apply/paint/render compute shaders.
|
|
//
|
|
// Cell word (u32): bits 0-15 material index, 16-23 colour variation, 26 gas/fire horizontal direction.
|
|
// Per-cell extension (vec2): x = vertical velocity accumulator, y = horizontal velocity.
|
|
// Material table: 3 uvec4 per material
|
|
// [0] colour(ARGB), flags, density(float), liquid_gravity(float)
|
|
// [1] liquid_viscosity(int), liquid_damping(float), liquid_flow_speed(float),
|
|
// gas speeds packed: byte0 gas_speed, byte1 up, byte2 horizontal, byte3 down
|
|
// [2] lifetime(int), durability(float), burn word 1 (fire_hp | burnable << 16 | on_fire << 17 | extinguishes << 18), burn word 2 (autoignition | temperature_of_fire << 8 | smoke << 16)
|
|
// The last entry of the table is special: (fire id, smoke id, steam id, material count).
|
|
layout(std430, set = 0, binding = 0) buffer Cells { uint cells[]; };
|
|
layout(std430, set = 0, binding = 1) readonly buffer Mats { uvec4 mats[]; };
|
|
layout(std430, set = 0, binding = 2) buffer Pixels { uint pixels[]; };
|
|
layout(std430, set = 0, binding = 3) buffer Ext { vec2 ext[]; };
|
|
layout(std430, set = 0, binding = 42) buffer Birth { uint birth[]; }; // the frame a cell got its material (cell age = frame - birth, 0070ebf0 req_lifetime)
|
|
// Material stamp (high 16), CLiquidCell movement state (bits 8..11), rest age (low byte).
|
|
layout(std430, set = 0, binding = 65) buffer TerrainAge { uint terrain_age[]; };
|
|
layout(std430, set = 0, binding = 4) buffer Claims { uint claims[]; };
|
|
// per cell: x = target index | (flip direction << 31), y = priority, z/w = new vy/vx bits
|
|
layout(std430, set = 0, binding = 5) buffer Intent { uvec4 intent[]; };
|
|
|
|
layout(push_constant) uniform PC {
|
|
int gw, gh; // grid size in cells
|
|
int ow, oh; // output size in pixels
|
|
int scale; // pixels per cell
|
|
int frame;
|
|
int pass_; // movement pass within the frame
|
|
int brush_x, brush_y, brush_r;
|
|
int brush_mat; // -1: none, 0: erase
|
|
int seed;
|
|
int view_x, view_y; // world cell at the top-left of the grid
|
|
int area_ox, area_oy; // world cell at the centre of wang pixel (0,0)
|
|
int pw, ph; // wang plane size
|
|
int m_rock, m_soil, m_sand, m_wet; // fill materials
|
|
int shift_x, shift_y, shift_mode;
|
|
int scene_x0, scene_y0, scene_w, scene_h; // pixel-scene plane placement (cells)
|
|
int bg_w, bg_h; // biome background tile size (0 = none)
|
|
int ent_count; // sprite instances for sprites.comp // terrain.comp: mode 1 = scroll by (shift_x, shift_y), keep the overlap
|
|
} pc;
|
|
|
|
const uint F_STATIC = 1u; // never moves (solid or liquid_static)
|
|
const uint F_LIQUID = 2u; // liquid or powder
|
|
const uint F_GAS = 4u;
|
|
const uint F_SAND = 8u; // powder (liquid_sand)
|
|
const uint F_AIR = 16u;
|
|
const uint F_FIRE = 32u;
|
|
const uint F_LIQCELL = 128u; // cell_type liquid, static or not (the native count / immersion predicate: liquid slot 22 true, powder slot 25 false)
|
|
const uint F_POWDER = 256u; // liquid_sand, static or not
|
|
const uint F_STAINS = 512u; // liquid_stains: a body in it takes its stain (vine points: the stored material that slows them)
|
|
const uint F_NOSTAIN = 2048u; // CellData stainable off (the box2d materials): no explosion burn
|
|
const uint F_INDESTRUCT = 1024u; // material tag [indestructible]: a CellEaterComponent with ignored_material_tag leaves it
|
|
const uint F_SLIME = 64u; // liquid_slime: moved by 0070b7c0 (docs/IMPLEMENTATION_BLOCKERS.md)
|
|
const uint NONE = 0xFFFFFFFFu;
|
|
const uint DIR_BIT = 1u << 26;
|
|
const uint BURN_BIT = 1u << 27; // the cell is burning
|
|
const uint FROZEN_BIT = 1u << 26; // a static cell stained frozen (MagicConvertMaterialComponent stain_frozen; bits 24-25 then hold its damage level, explode_rays.comp)
|
|
const uint ATTACH_BIT = 1u << 26; // a powder attached to a wall or ceiling (passive: byte 22 of the original cell); bits 24-25 then hold the direction: 1 right (state 5), 2 above (6), 3 left (7)
|
|
// Fire fade (the engine's signed fade byte, in steps of 4): bits 24-25 and 28-31 of the cell word. Burning cells and flames carry it.
|
|
uint cell_fade6(uint c) { return ((c >> 28) & 15u) | (((c >> 24) & 3u) << 4); }
|
|
uint with_fade6(uint c, uint f) { f = min(f, 63u); return (c & ~0xF3000000u) | ((f & 15u) << 28) | ((f >> 4) << 24); }
|
|
|
|
// The age of a cell and its fire fade share the birth word: bits 0-23 the frame it got its material (the age is the difference modulo 2^24), bits 24-31 the engine's signed fade byte (cell + 0x11).
|
|
const uint BIRTH_MASK = 0xFFFFFFu;
|
|
uint birth_frame() { return uint(pc.frame) & BIRTH_MASK; }
|
|
uint birth_age(uint b) { return (uint(pc.frame) - b) & BIRTH_MASK; }
|
|
int fade_of(uint b) { return int(b) >> 24; } // signed byte
|
|
uint with_fade(uint b, int f) { return (b & BIRTH_MASK) | (uint(f & 255) << 24); }
|
|
|
|
uint cell_mat(uint c) { return c & 0xFFFFu; }
|
|
uint mflags(uint m) { return mats[3u * m].y; }
|
|
// 0070b1d0: state 3 and zero vertical accumulator; support is not probed.
|
|
uint liquid_state(uint i, uint m) {
|
|
return (terrain_age[i] >> 16) == m ? (terrain_age[i] >> 8) & 15u : 3u;
|
|
}
|
|
bool liquid_freeze_ready(ivec2 p, uint c) {
|
|
const uint m = cell_mat(c);
|
|
const int i = p.y * pc.gw + p.x;
|
|
return (mflags(m) & F_LIQCELL) == 0u || (liquid_state(uint(i), m) == 3u && ext[i].x == 0.0);
|
|
}
|
|
// ChangeMaterial preserves the movement accumulators for nonburning same-class cells.
|
|
void material_changed(int i, uint oldCell, uint m) {
|
|
const uint old = cell_mat(oldCell);
|
|
const uint classMask = F_LIQCELL | F_GAS | F_FIRE | F_AIR;
|
|
const bool sameClass = (oldCell & BURN_BIT) == 0u && (mflags(old) & classMask) == (mflags(m) & classMask);
|
|
terrain_age[i] = (m << 16) | (sameClass && (terrain_age[i] >> 16) == old ? (terrain_age[i] & 0xFFFFu) : 0x300u);
|
|
if (!sameClass) ext[i] = vec2(0.0);
|
|
birth[i] = birth_frame();
|
|
}
|
|
float mdensity(uint m) { return uintBitsToFloat(mats[3u * m].z); }
|
|
float mgravity(uint m) { return uintBitsToFloat(mats[3u * m].w); }
|
|
int mviscosity(uint m) { return int(mats[3u * m + 1u].x & 0xFFFFu); }
|
|
uint mceiling(uint m) { return mats[3u * m + 1u].x >> 16; } // liquid_sticks_to_ceiling (powders)
|
|
float mdamping(uint m) { return uintBitsToFloat(mats[3u * m + 1u].y); }
|
|
float mflow(uint m) { return uintBitsToFloat(mats[3u * m + 1u].z); }
|
|
uint mgasbits(uint m) { return mats[3u * m + 1u].w; }
|
|
int mlifetime(uint m) { return int(mats[3u * m + 2u].x); }
|
|
|
|
uint hash(uint x) {
|
|
x ^= x >> 16; x *= 0x7feb352du;
|
|
x ^= x >> 15; x *= 0x846ca68bu;
|
|
x ^= x >> 16;
|
|
return x;
|
|
}
|
|
uint hash3(uint a, uint b, uint c) { return hash(a * 0x9E3779B1u ^ hash(b + 0x85EBCA6Bu ^ hash(c))); }
|