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;
//...