Fantasy-Map-Generator/src/layers/renderers/drawIce.js

73 lines
2.8 KiB
JavaScript

import {getGridPolygon} from "/src/utils/graphUtils";
export function drawIce() {
const {cells, vertices} = grid;
const {temp, h} = cells;
const n = cells.i.length;
const used = new Uint8Array(cells.i.length);
Math.random = aleaPRNG(seed);
const shieldMin = -8; // max temp to form ice shield (glacier)
const icebergMax = 1; // max temp to form an iceberg
for (const i of grid.cells.i) {
const t = temp[i];
if (t > icebergMax) continue; // too warm: no ice
if (t > shieldMin && h[i] >= 20) continue; // non-glacier land: no ice
if (t <= shieldMin) {
// very cold: ice shield
if (used[i]) continue; // already rendered
const onborder = cells.c[i].some(n => temp[n] > shieldMin);
if (!onborder) continue; // need to start from onborder cell
const vertex = cells.v[i].find(v => vertices.c[v].some(i => temp[i] > shieldMin));
const chain = connectVertices(vertex);
if (chain.length < 3) continue;
const points = clipPoly(chain.map(v => vertices.p[v]));
ice.append("polygon").attr("points", points).attr("type", "iceShield");
continue;
}
// mildly cold: iceberd
if (P(normalize(t, -7, 2.5))) continue; // t[-5; 2] cold: skip some cells
if (grid.features[cells.f[i]].type === "lake") continue; // lake: no icebers
let size = (6.5 + t) / 10; // iceberg size: 0 = full size, 1 = zero size
if (cells.t[i] === -1) size *= 1.3; // coasline: smaller icebers
size = Math.min(size * (0.4 + rand() * 1.2), 0.95); // randomize iceberg size
resizePolygon(i, size);
}
function resizePolygon(i, s) {
const c = grid.points[i];
const points = getGridPolygon(i).map(p => [(p[0] + (c[0] - p[0]) * s) | 0, (p[1] + (c[1] - p[1]) * s) | 0]);
ice
.append("polygon")
.attr("points", points)
.attr("cell", i)
.attr("size", rn(1 - s, 2));
}
// connect vertices to chain
function connectVertices(start) {
const chain = []; // vertices chain to form a path
for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) {
const prev = last(chain); // previous vertex in chain
chain.push(current); // add current vertex to sequence
const c = vertices.c[current]; // cells adjacent to vertex
c.filter(c => temp[c] <= shieldMin).forEach(c => (used[c] = 1));
const c0 = c[0] >= n || temp[c[0]] > shieldMin;
const c1 = c[1] >= n || temp[c[1]] > shieldMin;
const c2 = c[2] >= n || temp[c[2]] > shieldMin;
const v = vertices.v[current]; // neighboring vertices
if (v[0] !== prev && c0 !== c1) current = v[0];
else if (v[1] !== prev && c1 !== c2) current = v[1];
else if (v[2] !== prev && c0 !== c2) current = v[2];
if (current === chain[chain.length - 1]) {
ERROR && console.error("Next vertex is not found");
break;
}
}
return chain;
}
}