mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 01:41:22 +01:00
addLakesInDeepDepressions
This commit is contained in:
parent
6cca0b7f38
commit
c8c1c24909
5 changed files with 113 additions and 39 deletions
|
|
@ -1358,9 +1358,9 @@
|
|||
<input id="renderOcean" class="checkbox" type="checkbox">
|
||||
<label for="renderOcean" class="checkbox-label">Render ocean cells</label>
|
||||
</div>
|
||||
<div id="changeHeightsBox" data-tip="Regenerate rivers and allow water flow to slightly change heights">
|
||||
<input id="changeHeights" class="checkbox" type="checkbox" checked>
|
||||
<label for="changeHeights" class="checkbox-label">Allow water erosion</label>
|
||||
<div id="allowErosionBox" data-tip="Regenerate rivers and allow water flow to change heights and form lakes">
|
||||
<input id="allowErosion" class="checkbox" type="checkbox" checked>
|
||||
<label for="allowErosion" class="checkbox-label">Allow water erosion</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
65
main.js
65
main.js
|
|
@ -598,6 +598,7 @@ function generate() {
|
|||
HeightmapGenerator.generate();
|
||||
markFeatures();
|
||||
markupGridOcean();
|
||||
addLakesInDeepDepressions();
|
||||
openNearSeaLakes();
|
||||
|
||||
OceanLayers();
|
||||
|
|
@ -770,11 +771,71 @@ function markup(cells, start, increment, limit) {
|
|||
}
|
||||
}
|
||||
|
||||
function addLakesInDeepDepressions() {
|
||||
console.time("addLakesInDeepDepressions");
|
||||
const {cells, features, points} = grid;
|
||||
const {c, h, b} = cells;
|
||||
const ELEVATION_LIMIT = 10;
|
||||
|
||||
for (const i of cells.i) {
|
||||
if (b[i] || h[i] < 20) continue;
|
||||
|
||||
const minHeight = d3.min(c[i].map(c => h[c]));
|
||||
if (h[i] > minHeight) continue;
|
||||
|
||||
let deep = true;
|
||||
const treshold = h[i] + ELEVATION_LIMIT;
|
||||
const queue = [i];
|
||||
const checked = [];
|
||||
checked[i] = true;
|
||||
|
||||
// check if elevated cell can potentially pour to water
|
||||
while (deep && queue.length) {
|
||||
const q = queue.pop();
|
||||
|
||||
for (const n of c[q]) {
|
||||
if (checked[n]) continue;
|
||||
if (h[n] < 20) {
|
||||
deep = false;
|
||||
break;
|
||||
}
|
||||
if (h[n] >= treshold) continue;
|
||||
|
||||
checked[n] = true;
|
||||
queue.push(n);
|
||||
}
|
||||
}
|
||||
|
||||
// if not, add a lake
|
||||
if (deep) {
|
||||
debug.append("circle").attr("cx", points[i][0]).attr("cy", points[i][1]).attr("r", 1).attr("fill", "red");
|
||||
const lakeCells = [i].concat(c[i].filter(n => h[n] === h[i]));
|
||||
addLake(lakeCells);
|
||||
}
|
||||
}
|
||||
|
||||
function addLake(lakeCells) {
|
||||
const f = features.length;
|
||||
|
||||
lakeCells.forEach(i => {
|
||||
cells.h[i] = 19;
|
||||
cells.t[i] = -1;
|
||||
cells.f[i] = f;
|
||||
c[i].forEach(n => !lakeCells.includes(n) && (cells.t[c] = 1));
|
||||
});
|
||||
|
||||
features.push({i: f, land: false, border: false, type: "lake"});
|
||||
}
|
||||
|
||||
console.timeEnd("addLakesInDeepDepressions");
|
||||
}
|
||||
|
||||
// near sea lakes usually get a lot of water inflow, most of them should brake treshold and flow out to sea (see Ancylus Lake)
|
||||
function openNearSeaLakes() {
|
||||
if (templateInput.value === "Atoll") return; // no need for Atolls
|
||||
const cells = grid.cells,
|
||||
features = grid.features;
|
||||
|
||||
const cells = grid.cells;
|
||||
const features = grid.features;
|
||||
if (!features.find(f => f.type === "lake")) return; // no lakes
|
||||
TIME && console.time("openLakes");
|
||||
const LIMIT = 22; // max height that can be breached by water
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global.OceanLayers = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
typeof exports === "object" && typeof module !== "undefined" ? (module.exports = factory()) : typeof define === "function" && define.amd ? define(factory) : (global.OceanLayers = factory());
|
||||
})(this, function () {
|
||||
"use strict";
|
||||
|
||||
let cells, vertices, pointsN, used;
|
||||
|
||||
|
|
@ -12,11 +11,11 @@
|
|||
TIME && console.time("drawOceanLayers");
|
||||
|
||||
lineGen.curve(d3.curveBasisClosed);
|
||||
cells = grid.cells, pointsN = grid.cells.i.length, vertices = grid.vertices;
|
||||
(cells = grid.cells), (pointsN = grid.cells.i.length), (vertices = grid.vertices);
|
||||
const limits = outline === "random" ? randomizeOutline() : outline.split(",").map(s => +s);
|
||||
|
||||
const chains = [];
|
||||
const opacity = rn(.4 / limits.length, 2);
|
||||
const opacity = rn(0.4 / limits.length, 2);
|
||||
used = new Uint8Array(pointsN); // to detect already passed cells
|
||||
|
||||
for (const i of cells.i) {
|
||||
|
|
@ -29,10 +28,13 @@
|
|||
const chain = connectVertices(start, t); // vertices chain to form a path
|
||||
if (chain.length < 4) continue;
|
||||
const relax = 1 + t * -2; // select only n-th point
|
||||
const relaxed = chain.filter((v, i) => !(i%relax) || vertices.c[v].some(c => c >= pointsN));
|
||||
const relaxed = chain.filter((v, i) => !(i % relax) || vertices.c[v].some(c => c >= pointsN));
|
||||
if (relaxed.length < 4) continue;
|
||||
const points = clipPoly(relaxed.map(v => vertices.p[v]), 1);
|
||||
chains.push([t, points]);
|
||||
const points = clipPoly(
|
||||
relaxed.map(v => vertices.p[v]),
|
||||
1
|
||||
);
|
||||
chains.push([t, points]);
|
||||
}
|
||||
|
||||
for (const t of limits) {
|
||||
|
|
@ -48,14 +50,18 @@
|
|||
}
|
||||
|
||||
TIME && console.timeEnd("drawOceanLayers");
|
||||
}
|
||||
};
|
||||
|
||||
function randomizeOutline() {
|
||||
const limits = [];
|
||||
let odd = .2
|
||||
let odd = 0.2;
|
||||
for (let l = -9; l < 0; l++) {
|
||||
if (P(odd)) {odd = .2; limits.push(l);}
|
||||
else {odd *= 2;}
|
||||
if (P(odd)) {
|
||||
odd = 0.2;
|
||||
limits.push(l);
|
||||
} else {
|
||||
odd *= 2;
|
||||
}
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
|
@ -63,24 +69,26 @@
|
|||
// connect vertices to chain
|
||||
function connectVertices(start, t) {
|
||||
const chain = []; // vertices chain to form a path
|
||||
for (let i=0, current = start; i === 0 || current !== start && i < 10000; i++) {
|
||||
for (let i = 0, current = start; i === 0 || (current !== start && i < 10000); i++) {
|
||||
const prev = chain[chain.length - 1]; // previous vertex in chain
|
||||
chain.push(current); // add current vertex to sequence
|
||||
const c = vertices.c[current]; // cells adjacent to vertex
|
||||
c.filter(c => cells.t[c] === t).forEach(c => used[c] = 1);
|
||||
c.filter(c => cells.t[c] === t).forEach(c => (used[c] = 1));
|
||||
const v = vertices.v[current]; // neighboring vertices
|
||||
const c0 = !cells.t[c[0]] || cells.t[c[0]] === t-1;
|
||||
const c1 = !cells.t[c[1]] || cells.t[c[1]] === t-1;
|
||||
const c2 = !cells.t[c[2]] || cells.t[c[2]] === t-1;
|
||||
const c0 = !cells.t[c[0]] || cells.t[c[0]] === t - 1;
|
||||
const c1 = !cells.t[c[1]] || cells.t[c[1]] === t - 1;
|
||||
const c2 = !cells.t[c[2]] || cells.t[c[2]] === t - 1;
|
||||
if (v[0] !== undefined && v[0] !== prev && c0 !== c1) current = v[0];
|
||||
else if (v[1] !== undefined && v[1] !== prev && c1 !== c2) current = v[1];
|
||||
else if (v[2] !== undefined && v[2] !== prev && c0 !== c2) current = v[2];
|
||||
if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;}
|
||||
if (current === chain[chain.length - 1]) {
|
||||
ERROR && console.error("Next vertex is not found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
chain.push(chain[0]); // push first vertex as the last one
|
||||
return chain;
|
||||
}
|
||||
|
||||
return OceanLayers;
|
||||
|
||||
})));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
})(this, function () {
|
||||
"use strict";
|
||||
|
||||
const generate = function (changeHeights = true) {
|
||||
const generate = function (allowErosion = true) {
|
||||
TIME && console.time("generateRivers");
|
||||
Math.random = aleaPRNG(seed);
|
||||
const cells = pack.cells,
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
defineRivers();
|
||||
Lakes.cleanupLakeData();
|
||||
|
||||
if (changeHeights) cells.h = Uint8Array.from(h); // apply changed heights as basic one
|
||||
if (allowErosion) cells.h = Uint8Array.from(h); // apply changed heights as basic one
|
||||
|
||||
TIME && console.timeEnd("generateRivers");
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ function editHeightmap() {
|
|||
convertImage.style.display = type === "erase" ? "inline-block" : "none";
|
||||
|
||||
// hide erosion checkbox if mode is Keep
|
||||
changeHeightsBox.style.display = type === "keep" ? "none" : "inline-block";
|
||||
allowErosionBox.style.display = type === "keep" ? "none" : "inline-block";
|
||||
|
||||
// show finalize button
|
||||
if (!sessionStorage.getItem("noExitButtonAnimation")) {
|
||||
|
|
@ -182,19 +182,22 @@ function editHeightmap() {
|
|||
INFO && console.group("Edit Heightmap");
|
||||
TIME && console.time("regenerateErasedData");
|
||||
|
||||
const change = changeHeights.checked;
|
||||
const erosionAllowed = allowErosion.checked;
|
||||
markFeatures();
|
||||
markupGridOcean();
|
||||
if (change) openNearSeaLakes();
|
||||
if (erosionAllowed) {
|
||||
addLakesInDeepDepressions();
|
||||
openNearSeaLakes();
|
||||
}
|
||||
OceanLayers();
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
reGraph();
|
||||
drawCoastline();
|
||||
|
||||
Rivers.generate(change);
|
||||
Rivers.generate(erosionAllowed);
|
||||
|
||||
if (!change) {
|
||||
if (!erosionAllowed) {
|
||||
for (const i of pack.cells.i) {
|
||||
const g = pack.cells.g[i];
|
||||
if (pack.cells.h[i] !== grid.cells.h[g] && pack.cells.h[i] >= 20 === grid.cells.h[g] >= 20) pack.cells.h[i] = grid.cells.h[g];
|
||||
|
|
@ -236,6 +239,7 @@ function editHeightmap() {
|
|||
function restoreRiskedData() {
|
||||
INFO && console.group("Edit Heightmap");
|
||||
TIME && console.time("restoreRiskedData");
|
||||
const erosionAllowed = allowErosion.checked;
|
||||
|
||||
// assign pack data to grid cells
|
||||
const l = grid.cells.i.length;
|
||||
|
|
@ -250,7 +254,7 @@ function editHeightmap() {
|
|||
const culture = new Uint16Array(l);
|
||||
const religion = new Uint16Array(l);
|
||||
|
||||
// rivers data, stored only if changeHeights is unchecked
|
||||
// rivers data, stored only if allowErosion is unchecked
|
||||
const fl = new Uint16Array(l);
|
||||
const r = new Uint16Array(l);
|
||||
const conf = new Uint8Array(l);
|
||||
|
|
@ -268,7 +272,7 @@ function editHeightmap() {
|
|||
burg[g] = pack.cells.burg[i];
|
||||
religion[g] = pack.cells.religion[i];
|
||||
|
||||
if (!changeHeights.checked) {
|
||||
if (!erosionAllowed) {
|
||||
fl[g] = pack.cells.fl[i];
|
||||
r[g] = pack.cells.r[i];
|
||||
conf[g] = pack.cells.conf[i];
|
||||
|
|
@ -301,13 +305,14 @@ function editHeightmap() {
|
|||
|
||||
markFeatures();
|
||||
markupGridOcean();
|
||||
if (erosionAllowed) addLakesInDeepDepressions();
|
||||
OceanLayers();
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
reGraph();
|
||||
drawCoastline();
|
||||
|
||||
if (changeHeights.checked) Rivers.generate(changeHeights.checked);
|
||||
if (erosionAllowed) Rivers.generate(true);
|
||||
|
||||
// assign saved pack data from grid back to pack
|
||||
const n = pack.cells.i.length;
|
||||
|
|
@ -322,7 +327,7 @@ function editHeightmap() {
|
|||
pack.cells.religion = new Uint16Array(n);
|
||||
pack.cells.biome = new Uint8Array(n);
|
||||
|
||||
if (!changeHeights.checked) {
|
||||
if (!erosionAllowed) {
|
||||
pack.cells.r = new Uint16Array(n);
|
||||
pack.cells.conf = new Uint8Array(n);
|
||||
pack.cells.fl = new Uint16Array(n);
|
||||
|
|
@ -336,7 +341,7 @@ function editHeightmap() {
|
|||
pack.cells.biome[i] = land && biome[g] ? biome[g] : getBiomeId(grid.cells.prec[g], pack.cells.h[i]);
|
||||
|
||||
// rivers data
|
||||
if (!changeHeights.checked) {
|
||||
if (!erosionAllowed) {
|
||||
pack.cells.r[i] = r[g];
|
||||
pack.cells.conf[i] = conf[g];
|
||||
pack.cells.fl[i] = fl[g];
|
||||
|
|
@ -400,7 +405,7 @@ function editHeightmap() {
|
|||
drawStates();
|
||||
drawBorders();
|
||||
|
||||
if (changeHeights.checked) {
|
||||
if (erosion) {
|
||||
Rivers.specify();
|
||||
Lakes.generateName();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue