libpov_2025/minetest_biome_voronoi.html

224 lines
5.0 KiB
HTML
Raw Normal View History

2023-10-20 02:54:39 +02:00
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Minetest Biome Point Visualizer</title>
<style>
canvas {
border: 1px solid black;
}
</style>
2023-10-20 10:43:04 +02:00
<!-- Voronoi diagram API -->
2023-10-20 02:54:39 +02:00
<script src="./rhill-voronoi-core.js"></script>
</head>
<body>
<h1>Minetest Biome Point Visualizer</h1>
2023-10-20 10:43:04 +02:00
<div>
<!-- TODO: Add proper canvas browser fallback by listing the voronoi points -->
2023-10-20 02:54:39 +02:00
<canvas id="voronoiCanvas" width="900" height="900">
A voronoi diagram is supposed to be here but for some reason it cannot be displayed.
</canvas>
2023-10-20 10:43:04 +02:00
</div>
<div>
<form id="biomeForm">
<label>Biomes:<br>
<select id="biomeSelector" name="biomeList" size="16" multiple>
<option>Biome 1</option>
</select>
</label>
<br>
<button>Add</button>
<button>Remove</button>
<br>
<div>
<label>Heat:
<input id="inputHeat" type="number" value="50"></input>
</label>
<label>Humidity:
<input id="inputHumidity" type="number" value="50"></input>
</label>
<br>
<label>Min. Y:
<input id="minY" type="number" value="-31000"></input>
</label>
<label>Max. Y:
<input id="maxY" type="number" value="31000"></input>
</label>
</div>
</form>
<div>
2023-10-20 02:54:39 +02:00
<script>
"use strict";
let biomePoints = [
{ heat: 0, humidity: 0 },
{ heat: 50, humidity: 25 },
{ heat: -3, humidity: -59 },
{ heat: -100, humidity: -100 },
{ heat: 100, humidity: 100 },
{ heat: 100, humidity: 5 },
];
2023-10-20 10:43:04 +02:00
// FOREST-16 palette, plus black
const pointColor = "#913636";
const edgeColor = "#0f2c2e";
const gridColor = "#00000040";
const axisColor = "#000000";
const cellColors = [
"#64988e",
"#3d7085",
"#345644",
"#6b7f5c",
"#b0b17c",
"#e1c584",
"#c89660",
"#ad5f52",
"#692f11",
"#89542f",
"#796e63",
"#a17d5e",
"#b4a18f",
"#ecddba",
];
const fallbackCellColor = "#ecddba";
// define an array and randomize it
function shuffleArray(values) {
let index = values.length, randomIndex;
// While there remain elements to shuffle
while (index != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * index);
index--; // And swap it with the current element.
[values[index], values[randomIndex]] = [values[randomIndex], values[index]];
}
return values;
}
let colors = shuffleArray(cellColors);
// DEBUG: Random points
2023-10-20 02:54:39 +02:00
biomePoints = [];
for (let i=0; i<10; i++) {
biomePoints.push({
heat: Math.random()*200-100,
humidity: Math.random()*200-100,
});
}
function biomePointToVoronoiPoint(point) {
let newPoint = { x: point.heat, y: point.humidity }
return newPoint;
}
function voronoiPointToBiomePoint(point) {
let newPoint = { heat: point.x, humidity: point.y }
return newPoint;
}
function putPoint(context, point) {
context.moveTo(0, 0);
context.arc(point.heat, point.humidity, 2, 0, Math.PI * 2);
context.fill();
};
const LIMIT = 200
const GRID_STEP = 10
function putGrid(context) {
context.lineWidth = 0.5;
2023-10-20 10:43:04 +02:00
context.strokeStyle = gridColor;
2023-10-20 02:54:39 +02:00
for (let x=-LIMIT; x<=LIMIT; x+=GRID_STEP) {
context.beginPath();
context.moveTo(x, -LIMIT);
context.lineTo(x, LIMIT);
context.stroke();
}
for (let y=-LIMIT; y<=LIMIT; y+=GRID_STEP) {
context.beginPath();
context.moveTo(-LIMIT, y);
context.lineTo(LIMIT, y);
context.stroke();
}
}
function putAxes(context) {
context.lineWidth = 0.75;
// heat axis (horizontal)
context.beginPath();
context.moveTo(-LIMIT,0)
context.lineTo(LIMIT,0)
2023-10-20 10:43:04 +02:00
context.closePath();
2023-10-20 02:54:39 +02:00
context.stroke();
// humidity axis ()
context.beginPath();
context.moveTo(0,-LIMIT)
context.lineTo(0,LIMIT)
2023-10-20 10:43:04 +02:00
context.closePath();
2023-10-20 02:54:39 +02:00
context.stroke();
}
function draw() {
let canvas = document.getElementById("voronoiCanvas");
// TODO: Check for getContext support of browser
let context = canvas.getContext("2d")
context.translate(voronoiCanvas.width/2, voronoiCanvas.height/2);
context.scale(voronoiCanvas.width/300, voronoiCanvas.height/300);
let voronoi = new Voronoi();
let vbbox = {xl: -LIMIT, xr: LIMIT, yt: -LIMIT, yb: LIMIT};
let sites = []
for (let p of biomePoints) {
sites.push(biomePointToVoronoiPoint(p));
}
let diagram = voronoi.compute(sites, vbbox);
2023-10-20 10:43:04 +02:00
for (let c=0; c<diagram.cells.length; c++) {
let cell = diagram.cells[c]
if (c <= colors.length) {
context.fillStyle = colors[c];
} else {
context.fillStyle = fallbackColor;
}
context.beginPath();
for (let h=0; h<cell.halfedges.length; h++) {
let halfedge = cell.halfedges[h]
let start = halfedge.getStartpoint()
let end = halfedge.getEndpoint()
if (h === 0) {
context.moveTo(start.x, start.y);
} else {
context.lineTo(start.x, start.y);
}
context.lineTo(end.x, end.y);
}
context.closePath();
context.fill();
}
putAxes(context);
putGrid(context);
context.strokeStyle = edgeColor;
2023-10-20 02:54:39 +02:00
for (let e=0; e<diagram.edges.length; e++) {
let edge = diagram.edges[e];
context.beginPath();
context.moveTo(edge.va.x, edge.va.y);
context.lineTo(edge.vb.x, edge.vb.y);
2023-10-20 10:43:04 +02:00
context.closePath();
2023-10-20 02:54:39 +02:00
context.stroke();
}
2023-10-20 10:43:04 +02:00
context.fillStyle = pointColor;
for (let p of biomePoints) {
putPoint(context, p)
}
2023-10-20 02:54:39 +02:00
}
window.addEventListener("load", draw);
</script>
</body>
</html>