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