commandUpdate = regl({
frag: `
precision mediump float;
uniform sampler2D space;
const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
varying vec2 uv;
varying vec2 cellPosition;
const int ruleTableLength = 2 * 4;
int getSymmetryState(int n1, int n2, int n3) {
if (n1 == 0 && n2 == 0 && n3 == 0) { return 0; }
if (n1 == 0 && n2 == 0 && n3 == 1) { return 1; }
if (n1 == 0 && n2 == 0 && n3 == 2) { return 4; }
if (n1 == 0 && n2 == 1 && n3 == 0) { return 1; }
if (n1 == 0 && n2 == 1 && n3 == 1) { return 2; }
if (n1 == 0 && n2 == 1 && n3 == 2) { return 5; }
if (n1 == 0 && n2 == 2 && n3 == 0) { return 4; }
if (n1 == 0 && n2 == 2 && n3 == 1) { return 5; }
if (n1 == 0 && n2 == 2 && n3 == 2) { return 6; }
if (n1 == 1 && n2 == 0 && n3 == 0) { return 1; }
if (n1 == 1 && n2 == 0 && n3 == 1) { return 2; }
if (n1 == 1 && n2 == 0 && n3 == 2) { return 5; }
if (n1 == 1 && n2 == 1 && n3 == 0) { return 2; }
if (n1 == 1 && n2 == 1 && n3 == 1) { return 3; }
if (n1 == 1 && n2 == 1 && n3 == 2) { return 7; }
if (n1 == 1 && n2 == 2 && n3 == 0) { return 5; }
if (n1 == 1 && n2 == 2 && n3 == 1) { return 7; }
if (n1 == 1 && n2 == 2 && n3 == 2) { return 8; }
if (n1 == 2 && n2 == 0 && n3 == 0) { return 4; }
if (n1 == 2 && n2 == 0 && n3 == 1) { return 5; }
if (n1 == 2 && n2 == 0 && n3 == 2) { return 6; }
if (n1 == 2 && n2 == 1 && n3 == 0) { return 5; }
if (n1 == 2 && n2 == 1 && n3 == 1) { return 7; }
if (n1 == 2 && n2 == 1 && n3 == 2) { return 8; }
if (n1 == 2 && n2 == 2 && n3 == 0) { return 6; }
if (n1 == 2 && n2 == 2 && n3 == 1) { return 8; }
if (n1 == 2 && n2 == 2 && n3 == 2) { return 9; }
}
int getNextState(int c, int n1, int n2, int n3) {
int n = getSymmetryState(n1, n2, n3);
int stateCount = ${stateCount};
int combinedState = n * stateCount + c;
${ruleTableCode}
}
void main() {
int nextUpperCell = getNextState(
int(3.0 * texture2D(space, cellPosition * invRadius).g),
int(3.0 * texture2D(space, (cellPosition + vec2(1.0, 0.0)) * invRadius).r),
int(3.0 * texture2D(space, (cellPosition + vec2(0.0, -1.0)) * invRadius).r),
int(3.0 * texture2D(space, cellPosition * invRadius).r));
int nextLowerCell = getNextState(
int(3.0 * texture2D(space, cellPosition * invRadius).r),
int(3.0 * texture2D(space, (cellPosition + vec2(-1.0, 0.0)) * invRadius).g),
int(3.0 * texture2D(space, (cellPosition + vec2(0.0, 1.0)) * invRadius).g),
int(3.0 * texture2D(space, cellPosition * invRadius).g));
gl_FragColor = vec4(float(nextLowerCell) / 3.0, float(nextUpperCell) / 3.0, 0.0, 0.0);
}`,
vert: `
precision mediump float;
const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
attribute vec2 position;
varying vec2 uv;
varying vec2 cellPosition;
void main() {
uv = 0.5 * (position + 1.0);
cellPosition = uv * float(radius);
gl_Position = vec4(position, 0, 1);
}`,
uniforms: {
space: (_, { space }) => space
},
framebuffer: (_, { nextSpace }) => nextSpace,
attributes: { position: [-3, -1, 3, -1, 0, 2] },
count: 3,
depth: { enable: false }
})