Terrain

by oisyn

HTML

Arrow keys to move, pgup/pgdn to change altitude<br>
<canvas width=1024 height=576 id=canvas></canvas><br>
<canvas width=256 height=256 id=heightmap></canvas><br>

CSS

canvas { border: 1px solid black; }

JavaScript

const TerrainSize = 1024, TerrainMask = TerrainSize - 1;

var heightmap = new Float32Array(TerrainSize * TerrainSize);
var colormap;
var sample = (x, y) => heightmap[((y & TerrainMask) * TerrainSize) + (x & TerrainMask)];
var samplecolor = (x, y) => colormap[((y & TerrainMask) * TerrainSize) + (x & TerrainMask)];
var frnd = (min, max) => (max - min) * Math.random() + min;
var clamp = (x, min, max) => Math.min(Math.max(x, min), max);

const MaxHeight = 1024;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
const Width = canvas.width;
const Height = canvas.height;
const HalfWidth = Width / 2;
const HalfHeight = Height / 2;
var pixels = ctx.createImageData(Width, Height);
var pdata = new Uint32Array(pixels.data.buffer);

var hc = document.getElementById("heightmap");
hc.width = TerrainSize;
hc.height = TerrainSize;
hctx = hc.getContext("2d");
var himg = hctx.createImageData(TerrainSize, TerrainSize);
colormap = new Uint32Array(himg.data.buffer);
function put(x, y, v)
{
	heightmap[y * TerrainSize + x] = v;
}


// Diamond-Square
heightmap[0] = MaxHeight / 2;

let rndrange = MaxHeight;
for (let w = TerrainSize / 2, l = 1; w >= 1; w >>= 1, l++)
{
	const size = 2*w;
	rndrange *= 0.45;
	//if (w == 2)
//		rndrange *= 0.2;
	for (let y = 0; y < TerrainSize; y += size)
	{
		for (let x = 0; x < TerrainSize; x += size)
		{
			let mid = 0.25 * (sample(x, y) + sample(x+size, y) + sample(x, y+size) + sample(x+size, y+size));
			mid = clamp(mid + frnd(-rndrange, rndrange), 0, MaxHeight);
			put(x+w, y+w, mid);
		}
	}
			
	for (let y = 0; y < TerrainSize; y += size)
	{
		for (let x = 0; x < TerrainSize; x += size)
		{
			let px = x + w;
			let py = y;
			let mid = 0.25 * (sample(px - w, py) + sample(px + w, py) + sample(px, py - w) + sample(px, py + w));
			mid = clamp(mid + frnd(-rndrange*1.2, rndrange/1.2), 0, MaxHeight);
			put(px, py, mid);

			px = x;
			py = y + w;
			mid = 0.25 * (sample(px - w, py) + sample(px + w, py) + sample(px, py - w) +...