Skip to content

Instantly share code, notes, and snippets.

@robinhouston
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robinhouston/647eae82dd8d6d9ae71b to your computer and use it in GitHub Desktop.
Save robinhouston/647eae82dd8d6d9ae71b to your computer and use it in GitHub Desktop.
Close-up of the chequered grid
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Reaction-Diffusion</title>
<style>
body { margin: auto; width: 960px; height: 500px; overflow: hidden; }
#bg { width: 100%; height: 100%; }
</style>
</head>
<body>
<script>
var W = 120, H = 63, N = W*H, M = 8; // Tile dimensions
var doc = document.documentElement,
canvas = document.createElement("canvas"),
cx = canvas.getContext("2d"),
tile = document.createElement("canvas"),
tcx = tile.getContext("2d");
function init() {
tile.width = W;
tile.height = H;
canvas.width = W * M;
canvas.height = H * M;
document.body.appendChild(canvas);
initReactionDiffusion();
startReactionDiffusion();
}
function drawTiles() {
renderTile();
// This draws it blurrily:
// cx.drawImage(tile, 0, 0, W*M, H*M);
var timd = tcx.getImageData(0, 0, W, H),
td = timd.data,
imd = cx.createImageData(W * M, H * M),
d = imd.data;
for (var y=0; y<H*M; y++) {
for (var x=0; x<W*M; x++) {
var i = y*(W*M) + x,
j = ((y / M)|0)*W + ((x / M)|0);
d[4*i + 0] = td[4*j + 0];
d[4*i + 1] = td[4*j + 1];
d[4*i + 2] = td[4*j + 2];
d[4*i + 3] = td[4*j + 3];
}
}
cx.putImageData(imd, 0, 0);
}
var α, β, af, α1, β1, α2, β2, α3, β3, α4, β4, α_temp, β_temp;
function initReactionDiffusion() {
α = []; β = [];
for (var i=0; i<N; i++) {
α[i] = Math.random() * 100 - 50;
β[i] = Math.random() * 100 - 50;
}
α1 = []; α2 = []; α3 = []; α4 = [];
β1 = []; β2 = []; β3 = []; β4 = [];
α_temp = []; β_temp = [];
}
function frame() {
rk4(f, 0.1);
drawTiles();
af = requestAnimationFrame(frame);
}
function startReactionDiffusion() {
af = requestAnimationFrame(frame);
}
function renderTile() {
var imd = tcx.createImageData(W, H),
d = imd.data;
for (var i=0; i<N; i++) {
var v = ((α[i] + 2) * 25.5)|0;
d[4*i + 0] = v;
d[4*i + 1] = v/2;
d[4*i + 2] = v/2;
d[4*i + 3] = 0xFF;
}
tcx.putImageData(imd, 0, 0);
}
var clampMin = -10,
clampMax = 10,
D_a = 0.001,
D_b = 0.004,
abClampMin = -50,
abClampMax = 50;
function f(α_in, β_in, c, δα, δβ, δα_out, δβ_out) {
var α, β;
if (c == 0) {
α = α_in;
β = β_in;
} else {
α = α_temp;
β = β_temp;
for (var i=0; i<N; i++) {
α[i] = α_in[i] + c*δα[i];
β[i] = β_in[i] + c*δβ[i];
}
}
for (var y=0; y<H; y++) {
for (var x=0; x<W; x++) {
var i = W*y + x,
px = (x+W-1)%W, sx = (x+1)%W,
py = (y+H-1)%H, sy = (y+1)%H;
var laplacian_a = α[W*py+x] + α[W*y+sx] + α[W*sy+x] + α[W*y+px] - 4*α[i],
laplacian_b = β[W*py+x] + β[W*y+sx] + β[W*sy+x] + β[W*y+px] - 4*β[i];
δα_out[i] = Math.max(clampMin, Math.min(clampMax, (D_a * (α[i]*α[i] - β[i]*β[i])) + laplacian_b));
δβ_out[i] = Math.max(clampMin, Math.min(clampMax, (D_b * (2*α[i]*β[i])) - laplacian_a));
}
}
}
function rk4(f, h) {
f(α, β, 0, null, null, α1, β1);
f(α, β, h/2, α1, β1, α2, β2);
f(α, β, h/2, α2, β2, α3, β3);
f(α, β, h, α3, β3, α4, β4);
for (var i=0; i<N; i++) {
α[i] = Math.max(abClampMin, Math.min(abClampMax, α[i] + (h/6) * (α1[i] + 2*α2[i] + 2*α3[i] + α4[i]) ));
β[i] = Math.max(abClampMin, Math.min(abClampMax, β[i] + (h/6) * (β1[i] + 2*β2[i] + 2*β3[i] + β4[i]) ));
}
}
init();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment