pretty-automata/shaders/automaton.comp

104 lines
2.9 KiB
Plaintext

#version 460
layout (local_size_x = 1, local_size_y = 1) in;
uniform uvec2 dimensions;
uniform uint birth_rule;
uniform uint survive_rule;
uniform uint starve_delay;
uniform bool starve_recover;
uniform bool has_max_age;
layout (std430) restrict readonly buffer buffer_data_in
{
uint data_in[];
};
layout (std430) restrict buffer buffer_data_out
{
uint data_out[];
};
#include "cellstate_common.glsl"
bool check_condition(uint rule, uint count) {
return ((rule >> count) & uint(1)) == 1;
}
void main() {
uint data_size = dimensions.x * dimensions.y;
uint neighbour_count = 0;
for (int ix = -1; ix < 2; ix++) {
for (int iy = -1; iy < 2; iy++) {
int cx = int(gl_GlobalInvocationID.x) + ix;
int cy = int(gl_GlobalInvocationID.y) + iy;
if (cx < 0) {
cx += int(dimensions.x);
} else if (cx >= dimensions.x) {
cx -= int(dimensions.x);
}
if (cy < 0) {
cy += int(dimensions.y);
} else if (cy >= dimensions.y) {
cy -= int(dimensions.y);
}
uint pos = cx + cy * dimensions.x;
neighbour_count += cellstate_from_data(data_in[pos]).alive ? 1 : 0;
}
}
uint pos = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * dimensions.x;
CellState state = cellstate_from_data(data_in[pos]);
uint max_age = data_in[data_size + pos];
if (state.alive) {
if (starve_recover) {
if (check_condition(birth_rule, neighbour_count)) {
state.starving = false;
} else {
if (state.starving) {
state.starve_duration = state.starve_duration + 1;
} else {
state.starving = true;
state.starve_duration = 0;
}
}
} else {
if (!check_condition(survive_rule, neighbour_count)) {
if (state.starving) {
state.starve_duration = state.starve_duration + 1;
} else {
state.starving = true;
state.starve_duration = 0;
}
}
}
if (has_max_age && state.age >= max_age) {
state.alive = false;
state.starving = false;
state.age = 0;
state.starve_duration = 0;
}
if (state.starving && state.starve_duration == starve_delay) {
state.starving = false;
state.alive = false;
state.age = 0;
state.starve_duration = 0;
} else {
state.age = state.age + 1;
}
} else {
if (check_condition(birth_rule, neighbour_count)) {
state.alive = true;
state.age = 0;
}
}
data_out[pos] = cellstate_to_data(state);
// propagate max-age
data_out[data_size + pos] = data_in[data_size + pos];
}