mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
heightmap - fix issues
This commit is contained in:
parent
27a045b709
commit
ff31e23a27
5 changed files with 60 additions and 44 deletions
|
|
@ -1332,7 +1332,7 @@
|
|||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button id="templateSelect" data-tip="Select heightmap template or pre-made heightmap">Select</button>
|
||||
<button id="templateSelectButton" data-tip="Select heightmap template or pre-made heightmap">Select</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,10 @@ function insertEditorHtml() {
|
|||
const templatesHtml = templates
|
||||
.map(({id, name}) => {
|
||||
Math.random = aleaPRNG(seed);
|
||||
|
||||
HeightmapGenerator.resetHeights();
|
||||
const heights = HeightmapGenerator.fromTemplate(id);
|
||||
HeightmapGenerator.cleanup();
|
||||
const dataUrl = drawHeights(heights);
|
||||
|
||||
return /* html */ `<article data-id="${id}" data-seed="${seed}">
|
||||
|
|
@ -224,7 +227,9 @@ function regeneratePreview(article, id) {
|
|||
article.dataset.seed = seed;
|
||||
Math.random = aleaPRNG(seed);
|
||||
|
||||
HeightmapGenerator.resetHeights();
|
||||
const heights = HeightmapGenerator.fromTemplate(id);
|
||||
HeightmapGenerator.cleanup();
|
||||
const dataUrl = drawHeights(heights);
|
||||
article.querySelector("img").src = dataUrl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
window.HeightmapGenerator = (function () {
|
||||
let cells, p, heights;
|
||||
let heights = null;
|
||||
const setHeights = h => (heights = h);
|
||||
const resetHeights = () => (heights = new Uint8Array(grid.points.length));
|
||||
const getHeights = () => heights;
|
||||
const cleanup = () => (heights = null);
|
||||
|
||||
const generate = async function () {
|
||||
cells = grid.cells;
|
||||
p = grid.points;
|
||||
heights = new Uint8Array(grid.points.length);
|
||||
resetHeights();
|
||||
|
||||
const input = document.getElementById("templateInput");
|
||||
const selectedId = input.selectedIndex >= 0 ? input.selectedIndex : 0;
|
||||
|
|
@ -33,8 +35,8 @@ window.HeightmapGenerator = (function () {
|
|||
canvas.remove();
|
||||
img.remove();
|
||||
|
||||
cells.h = heights;
|
||||
heights = null;
|
||||
grid.cells.h = heights;
|
||||
cleanup();
|
||||
TIME && console.timeEnd("defineHeightmap");
|
||||
resolve();
|
||||
};
|
||||
|
|
@ -55,8 +57,8 @@ window.HeightmapGenerator = (function () {
|
|||
addStep(...elements);
|
||||
}
|
||||
|
||||
cells.h = heights;
|
||||
heights = null;
|
||||
grid.cells.h = heights;
|
||||
cleanup();
|
||||
TIME && console.timeEnd("generateHeightmap");
|
||||
};
|
||||
|
||||
|
|
@ -66,8 +68,6 @@ window.HeightmapGenerator = (function () {
|
|||
|
||||
if (!steps.length) throw new Error(`Heightmap template: no steps. Template: ${template}. Steps: ${steps}`);
|
||||
|
||||
heights = new Uint8Array(grid.points.length);
|
||||
|
||||
for (const step of steps) {
|
||||
const elements = step.trim().split(" ");
|
||||
if (elements.length < 2) throw new Error(`Heightmap template: steps < 2. Template: ${template}. Step: ${elements}`);
|
||||
|
|
@ -77,20 +77,21 @@ window.HeightmapGenerator = (function () {
|
|||
return heights;
|
||||
};
|
||||
|
||||
function addStep(a1, a2, a3, a4, a5) {
|
||||
if (a1 === "Hill") return addHill(a2, a3, a4, a5);
|
||||
if (a1 === "Pit") return addPit(a2, a3, a4, a5);
|
||||
if (a1 === "Range") return addRange(a2, a3, a4, a5);
|
||||
if (a1 === "Trough") return addTrough(a2, a3, a4, a5);
|
||||
if (a1 === "Strait") return addStrait(a2, a3);
|
||||
if (a1 === "Mask") return mask(a2);
|
||||
if (a1 === "Add") return modify(a3, +a2, 1);
|
||||
if (a1 === "Multiply") return modify(a3, 0, +a2);
|
||||
if (a1 === "Smooth") return smooth(a2);
|
||||
function addStep(tool, a2, a3, a4, a5) {
|
||||
if (tool === "Hill") return addHill(a2, a3, a4, a5);
|
||||
if (tool === "Pit") return addPit(a2, a3, a4, a5);
|
||||
if (tool === "Range") return addRange(a2, a3, a4, a5);
|
||||
if (tool === "Trough") return addTrough(a2, a3, a4, a5);
|
||||
if (tool === "Strait") return addStrait(a2, a3);
|
||||
if (tool === "Mask") return mask(a2);
|
||||
if (tool === "Invert") return invert(a2, a3);
|
||||
if (tool === "Add") return modify(a3, +a2, 1);
|
||||
if (tool === "Multiply") return modify(a3, 0, +a2);
|
||||
if (tool === "Smooth") return smooth(a2);
|
||||
}
|
||||
|
||||
function getBlobPower() {
|
||||
const cells = +pointsInput.dataset.cells;
|
||||
const cells = +byId("pointsInput").dataset.cells;
|
||||
if (cells === 1000) return 0.93;
|
||||
if (cells === 2000) return 0.95;
|
||||
if (cells === 5000) return 0.96;
|
||||
|
|
@ -107,7 +108,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
|
||||
function getLinePower() {
|
||||
const cells = +pointsInput.dataset.cells;
|
||||
const cells = +byId("pointsInput").dataset.cells;
|
||||
if (cells === 1000) return 0.74;
|
||||
if (cells === 2000) return 0.75;
|
||||
if (cells === 5000) return 0.78;
|
||||
|
|
@ -149,7 +150,7 @@ window.HeightmapGenerator = (function () {
|
|||
while (queue.length) {
|
||||
const q = queue.shift();
|
||||
|
||||
for (const c of cells.c[q]) {
|
||||
for (const c of grid.cells.c[q]) {
|
||||
if (change[c]) continue;
|
||||
change[c] = change[q] ** power * (Math.random() * 0.2 + 0.9);
|
||||
if (change[c] > 1) queue.push(c);
|
||||
|
|
@ -186,7 +187,7 @@ window.HeightmapGenerator = (function () {
|
|||
h = h ** getBlobPower() * (Math.random() * 0.2 + 0.9);
|
||||
if (h < 1) return;
|
||||
|
||||
cells.c[q].forEach(function (c, i) {
|
||||
grid.cells.c[q].forEach(function (c, i) {
|
||||
if (used[c]) return;
|
||||
heights[c] = lim(heights[c] - h * (Math.random() * 0.2 + 0.9));
|
||||
used[c] = 1;
|
||||
|
|
@ -228,11 +229,12 @@ window.HeightmapGenerator = (function () {
|
|||
// get main ridge
|
||||
function getRange(cur, end) {
|
||||
const range = [cur];
|
||||
const p = grid.points;
|
||||
used[cur] = 1;
|
||||
|
||||
while (cur !== end) {
|
||||
let min = Infinity;
|
||||
cells.c[cur].forEach(function (e) {
|
||||
grid.cells.c[cur].forEach(function (e) {
|
||||
if (used[e]) return;
|
||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||
if (Math.random() > 0.85) diff = diff / 2;
|
||||
|
|
@ -261,7 +263,7 @@ window.HeightmapGenerator = (function () {
|
|||
h = h ** power - 1;
|
||||
if (h < 2) break;
|
||||
frontier.forEach(f => {
|
||||
cells.c[f].forEach(i => {
|
||||
grid.cells.c[f].forEach(i => {
|
||||
if (!used[i]) {
|
||||
queue.push(i);
|
||||
used[i] = 1;
|
||||
|
|
@ -274,7 +276,7 @@ window.HeightmapGenerator = (function () {
|
|||
range.forEach((cur, d) => {
|
||||
if (d % 6 !== 0) return;
|
||||
for (const l of d3.range(i)) {
|
||||
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => heights[a] - heights[b])]; // downhill cell
|
||||
const min = grid.cells.c[cur][d3.scan(grid.cells.c[cur], (a, b) => heights[a] - heights[b])]; // downhill cell
|
||||
heights[min] = (heights[cur] * 2 + heights[min]) / 3;
|
||||
cur = min;
|
||||
}
|
||||
|
|
@ -322,11 +324,12 @@ window.HeightmapGenerator = (function () {
|
|||
// get main ridge
|
||||
function getRange(cur, end) {
|
||||
const range = [cur];
|
||||
const p = grid.points;
|
||||
used[cur] = 1;
|
||||
|
||||
while (cur !== end) {
|
||||
let min = Infinity;
|
||||
cells.c[cur].forEach(function (e) {
|
||||
grid.cells.c[cur].forEach(function (e) {
|
||||
if (used[e]) return;
|
||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||
if (Math.random() > 0.8) diff = diff / 2;
|
||||
|
|
@ -355,7 +358,7 @@ window.HeightmapGenerator = (function () {
|
|||
h = h ** power - 1;
|
||||
if (h < 2) break;
|
||||
frontier.forEach(f => {
|
||||
cells.c[f].forEach(i => {
|
||||
grid.cells.c[f].forEach(i => {
|
||||
if (!used[i]) {
|
||||
queue.push(i);
|
||||
used[i] = 1;
|
||||
|
|
@ -368,7 +371,7 @@ window.HeightmapGenerator = (function () {
|
|||
range.forEach((cur, d) => {
|
||||
if (d % 6 !== 0) return;
|
||||
for (const l of d3.range(i)) {
|
||||
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => heights[a] - heights[b])]; // downhill cell
|
||||
const min = grid.cells.c[cur][d3.scan(grid.cells.c[cur], (a, b) => heights[a] - heights[b])]; // downhill cell
|
||||
//debug.append("circle").attr("cx", p[min][0]).attr("cy", p[min][1]).attr("r", 1);
|
||||
heights[min] = (heights[cur] * 2 + heights[min]) / 3;
|
||||
cur = min;
|
||||
|
|
@ -394,10 +397,11 @@ window.HeightmapGenerator = (function () {
|
|||
|
||||
function getRange(cur, end) {
|
||||
const range = [];
|
||||
const p = grid.points;
|
||||
|
||||
while (cur !== end) {
|
||||
let min = Infinity;
|
||||
cells.c[cur].forEach(function (e) {
|
||||
grid.cells.c[cur].forEach(function (e) {
|
||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||
if (Math.random() > 0.8) diff = diff / 2;
|
||||
if (diff < min) {
|
||||
|
|
@ -416,7 +420,7 @@ window.HeightmapGenerator = (function () {
|
|||
while (width > 0) {
|
||||
const exp = 0.9 - step * width;
|
||||
range.forEach(function (r) {
|
||||
cells.c[r].forEach(function (e) {
|
||||
grid.cells.c[r].forEach(function (e) {
|
||||
if (used[e]) return;
|
||||
used[e] = 1;
|
||||
query.push(e);
|
||||
|
|
@ -448,7 +452,7 @@ window.HeightmapGenerator = (function () {
|
|||
const smooth = (fr = 2, add = 0) => {
|
||||
heights = heights.map((h, i) => {
|
||||
const a = [h];
|
||||
cells.c[i].forEach(c => a.push(heights[c]));
|
||||
grid.cells.c[i].forEach(c => a.push(heights[c]));
|
||||
if (fr === 1) return d3.mean(a) + add;
|
||||
return lim((h * (fr - 1) + d3.mean(a) + add) / fr);
|
||||
});
|
||||
|
|
@ -458,7 +462,7 @@ window.HeightmapGenerator = (function () {
|
|||
const fr = power ? Math.abs(power) : 1;
|
||||
|
||||
heights = heights.map((h, i) => {
|
||||
const [x, y] = p[i];
|
||||
const [x, y] = grid.points[i];
|
||||
const nx = (2 * x) / graphWidth - 1; // [-1, 1], 0 is center
|
||||
const ny = (2 * y) / graphHeight - 1; // [-1, 1], 0 is center
|
||||
let distance = (1 - nx ** 2) * (1 - ny ** 2); // 1 is center, 0 is edge
|
||||
|
|
@ -500,12 +504,12 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
|
||||
function assignColorsToHeight(imageData) {
|
||||
for (let i = 0; i < cells.i.length; i++) {
|
||||
for (let i = 0; i < grid.cells.i.length; i++) {
|
||||
const lightness = imageData[i * 4] / 255;
|
||||
const powered = lightness < 0.2 ? lightness : 0.2 + (lightness - 0.2) ** 0.8;
|
||||
heights[i] = minmax(Math.floor(powered * 100), 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
return {generate, fromTemplate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask, invert};
|
||||
return {setHeights, resetHeights, getHeights, cleanup, generate, fromTemplate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask, invert};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -652,17 +652,24 @@ function editHeightmap() {
|
|||
if (Number.isNaN(operand)) return tip("Operand should be a number", false, "error");
|
||||
if ((operator === "add" || operator === "subtract") && !Number.isInteger(operand)) return tip("Operand should be an integer", false, "error");
|
||||
|
||||
HeightmapGenerator.setHeights(grid.cells.h);
|
||||
|
||||
if (operator === "multiply") HeightmapGenerator.modify(range, 0, operand, 0);
|
||||
else if (operator === "divide") HeightmapGenerator.modify(range, 0, 1 / operand, 0);
|
||||
else if (operator === "add") HeightmapGenerator.modify(range, operand, 1, 0);
|
||||
else if (operator === "subtract") HeightmapGenerator.modify(range, -1 * operand, 1, 0);
|
||||
else if (operator === "exponent") HeightmapGenerator.modify(range, 0, 1, operand);
|
||||
|
||||
grid.cells.h = HeightmapGenerator.getHeights();
|
||||
HeightmapGenerator.cleanup();
|
||||
updateHeightmap();
|
||||
}
|
||||
|
||||
function smoothAllHeights() {
|
||||
HeightmapGenerator.setHeights(grid.cells.h);
|
||||
HeightmapGenerator.smooth(4, 1.5);
|
||||
grid.cells.h = HeightmapGenerator.getHeights();
|
||||
HeightmapGenerator.cleanup();
|
||||
updateHeightmap();
|
||||
}
|
||||
|
||||
|
|
@ -879,10 +886,7 @@ function editHeightmap() {
|
|||
const steps = body.querySelectorAll("div").length;
|
||||
const changed = +body.getAttribute("data-changed");
|
||||
const template = e.target.value;
|
||||
if (!steps || !changed) {
|
||||
changeTemplate(template);
|
||||
return;
|
||||
}
|
||||
if (!steps || !changed) return changeTemplate(template);
|
||||
|
||||
alertMessage.innerHTML = "Are you sure you want to select a different template? All changes will be lost.";
|
||||
$("#alert").dialog({
|
||||
|
|
@ -921,10 +925,10 @@ function editHeightmap() {
|
|||
const steps = byId("templateBody").querySelectorAll("#templateBody > div");
|
||||
if (!steps.length) return;
|
||||
|
||||
grid.cells.h = new Uint8Array(grid.cells.i.length); // clean all heights
|
||||
|
||||
const seed = byId("templateSeed").value;
|
||||
if (seed) Math.random = aleaPRNG(seed);
|
||||
|
||||
HeightmapGenerator.resetHeights();
|
||||
restartHistory();
|
||||
|
||||
for (const step of steps) {
|
||||
|
|
@ -948,9 +952,12 @@ function editHeightmap() {
|
|||
else if (type === "Multiply") HeightmapGenerator.modify(dist, 0, +count);
|
||||
else if (type === "Smooth") HeightmapGenerator.smooth(+count);
|
||||
|
||||
grid.cells.h = HeightmapGenerator.getHeights();
|
||||
updateHistory("noStat"); // update history on every step
|
||||
}
|
||||
|
||||
grid.cells.h = HeightmapGenerator.getHeights();
|
||||
HeightmapGenerator.cleanup();
|
||||
updateStatistics();
|
||||
mockHeightmap();
|
||||
if (byId("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ optionsContent.addEventListener("click", function (event) {
|
|||
else if (id === "optionsMapHistory") showSeedHistoryDialog();
|
||||
else if (id === "optionsCopySeed") copyMapURL();
|
||||
else if (id === "optionsEraRegenerate") regenerateEra();
|
||||
else if (id === "templateSelect") openTemplateSelectionDialog();
|
||||
else if (id === "templateSelectButton") openTemplateSelectionDialog();
|
||||
else if (id === "zoomExtentDefault") restoreDefaultZoomExtent();
|
||||
else if (id === "translateExtent") toggleTranslateExtent(event.target);
|
||||
else if (id === "speakerTest") testSpeaker();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue