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

function mulberry32(seed)
{
	return function()
	{
		seed = (seed + 0x9e3779b9) | 0;  // the `| 0` coerces it into a 32-bit int
		let z = seed;
		z ^= z >>> 16;
		z = Math.imul(z, 0x21f0aaad);
		z ^= z >>> 15;
		z = Math.imul(z, 0x735a2d97);
		z ^= z >>> 15;
		return (z >>> 0) / 0x100000000;
	}
}

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)];
let rnd = mulberry32(0);
var frnd = (min, max) => (max - min) * rnd() + min;
var clamp = (x, min, max) => Math.min(Math.max(x, min), max);

const MaxHeight = 1024;//TerrainSize;
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/2;
for (let w = TerrainSize / 2, l = 1; w >= 1; w >>= 1, l++)
{
	const size = 2*w;
	if (size <= MaxHeight)
		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 <...