DiamondSquare canvas

by IceCreamYou

CSS

canvas {
  border: 1px solid red;
}

JavaScript

var size = 512;

function makeCanvas(w, h) {
    var canvas = document.createElement('canvas'),
        context = canvas.getContext('2d'),
        i,
        l;

		canvas.width = w;
    canvas.height = h;
    // Only previously touched pixels are modifiable when writing imageData
    context.fillRect(0, 0, w, h);

		var imageData = context.getImageData(0, 0, w, h),
    		pixels = imageData.data;

    diamondSquare(pixels, w, h);

		context.putImageData(imageData, 0, 0);
  	return canvas;
}

document.body.appendChild(makeCanvas(size, size));

// =======================================================

/**
 * Returns the power of two that is closest to `value` without being lower.
 *
 * From https://github.com/mrdoob/three.js/blob/d37e7b8f689e90b713c33c3754cece92779d96f7/src/math/Math.js#L158-L170
 */
function nextPowerOfTwo(value) {
    value --;
    value |= value >> 1;
    value |= value >> 2;
    value |= value >> 4;
    value |= value >> 8;
    value |= value >> 16;
    value ++;
    return value;
}

/**
 * Generates noise using the Diamond-Square algorithm.
 *
 * From https://github.com/IceCreamYou/THREE.Terrain/blob/6e8e149e5efc20e09fd5ea84379d0ded9d4e1eb8/src/generators.js#L100-L178
 */
function diamondSquare(pixels, w, h) {
    // Set the segment length to the smallest power of 2 that is greater than
    // the number of vertices in either dimension of the plane
    var segments = nextPowerOfTwo(Math.max(w, h) + 1);

    // Initialize heightmap
    var size = segments + 1,
        heightmap = [],
        smoothing = 256, // max height - min height
        i,
        j,
        xl = w + 1,
        yl = h + 1;
    for (i = 0; i <= segments; i++) {
        heightmap[i] = new Float64Array(segments+1);
    }

    // Generate heightmap
    for (var l = segments; l >= 2; l /= 2) {
        var half = Math.round(l*0.5),
            whole = Math.round(l),
            x,
            y,
            avg,
            d,
            e;
        smoothing /= 2;
        //...