Skip to content

Instantly share code, notes, and snippets.

@robinhouston
Last active October 27, 2019 19:15
Show Gist options
  • Save robinhouston/6027749 to your computer and use it in GitHub Desktop.
Save robinhouston/6027749 to your computer and use it in GitHub Desktop.
Algorithmic painting
<!DOCTYPE html>
<title>Maze flood fill</title>
<style>
canvas { display: block; margin: auto; }
</style>
<canvas width="1601" height="1001" style="display: none;"></canvas>
<canvas width="800" height="500"></canvas>
<script>
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
</script>
<script>
var PIXELS_PER_FRAME = 5;
var canvases = document.getElementsByTagName("canvas"),
canvas = canvases[0],
output = canvases[1];
var cx = canvas.getContext("2d"),
output_cx = output.getContext("2d");
function loadAndFill(image_url, finished) {
var image = new Image();
image.addEventListener("load", function() {
cx.drawImage(image, (canvas.width - image.width)/2, (canvas.height - image.height)/2);
floodFill(finished);
});
image.src = image_url;
}
var fill_color = {r: 0xFF, g: 0, b: 0};
function floodFill(finished) {
var image_data_object = cx.getImageData(0, 0, canvas.width, canvas.height),
image_data = image_data_object.data,
output_data_object = output_cx.getImageData(0, 0, output.width, output.height),
output_data = output_data_object.data;
function white(x, y) {
var base_index = (canvas.width * y + x) * 4,
r = image_data[base_index],
g = image_data[base_index + 1],
b = image_data[base_index + 2],
a = image_data[base_index + 3];
return (r == 0xFF && g == 0xFF && b == 0xFF);
}
function redden(x, y) {
var base_index = (canvas.width * y + x) * 4;
image_data[base_index] = fill_color.r;
image_data[base_index + 1] = fill_color.g;
image_data[base_index + 2] = fill_color.b;
image_data[base_index + 3] = 0xFF;
if ( x%2 == 1 && y%2 == 1) {
base_index = (output.width * (y-1)/2 + (x-1)/2)*4;
output_data[base_index] = fill_color.r;
output_data[base_index + 1] = fill_color.g;
output_data[base_index + 2] = fill_color.b;
output_data[base_index + 3] = 0xFF;
}
}
var x = 801, y = 501;
var queue = [[x,y]];
function doFill() {
var num_reddened = 0,
num_fronts = queue.length;
queue_loop: while (queue.length > 0) {
var p = queue.shift(), x = p[0], y = p[1];
if (!white(x, y)) continue;
while (x > 0 && white(x-1, y)) x--;
while (x < canvas.width && white(x, y)) {
redden(x, y);
if (y > 0 && white(x, y-1)) queue.push([x, y-1]);
if (y < canvas.height-1 && white(x, y+1)) queue.push([x, y+1]);
x++;
if (++num_reddened == PIXELS_PER_FRAME * num_fronts) {
queue.unshift([x, y]);
break queue_loop;
}
}
}
output_cx.putImageData(output_data_object, 0, 0);
}
function animate() {
doFill();
fill_color.r = (fill_color.r + 1) % 0x100;
fill_color.g = (fill_color.g + 0xFE) % 0x100;
if (queue.length > 0) requestAnimationFrame(animate);
else if (finished) finished();
}
requestAnimationFrame(animate);
}
// Maze image generated uniformly at random using Wilson’s algorithm, specifically:
// python make_1bit_maze.py -c 800 -r 500 -o 800x500.png
loadAndFill("800x500.png");
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment