diff --git a/heightmaps/africa-centric.png b/heightmaps/africa-centric.png
new file mode 100644
index 00000000..b493c3ad
Binary files /dev/null and b/heightmaps/africa-centric.png differ
diff --git a/heightmaps/arabia.png b/heightmaps/arabia.png
new file mode 100644
index 00000000..23e3e873
Binary files /dev/null and b/heightmaps/arabia.png differ
diff --git a/heightmaps/atlantics.png b/heightmaps/atlantics.png
new file mode 100644
index 00000000..04c2133a
Binary files /dev/null and b/heightmaps/atlantics.png differ
diff --git a/heightmaps/britain.png b/heightmaps/britain.png
new file mode 100644
index 00000000..0b5acfac
Binary files /dev/null and b/heightmaps/britain.png differ
diff --git a/heightmaps/caribbean.png b/heightmaps/caribbean.png
new file mode 100644
index 00000000..8f8c2fe5
Binary files /dev/null and b/heightmaps/caribbean.png differ
diff --git a/heightmaps/east-asia.png b/heightmaps/east-asia.png
new file mode 100644
index 00000000..8e929ae7
Binary files /dev/null and b/heightmaps/east-asia.png differ
diff --git a/heightmaps/eurasia.png b/heightmaps/eurasia.png
new file mode 100644
index 00000000..fcc6c3da
Binary files /dev/null and b/heightmaps/eurasia.png differ
diff --git a/heightmaps/europe-accented.png b/heightmaps/europe-accented.png
new file mode 100644
index 00000000..01820a95
Binary files /dev/null and b/heightmaps/europe-accented.png differ
diff --git a/heightmaps/europe-and-central-asia.png b/heightmaps/europe-and-central-asia.png
new file mode 100644
index 00000000..d9f420b3
Binary files /dev/null and b/heightmaps/europe-and-central-asia.png differ
diff --git a/heightmaps/europe-central.png b/heightmaps/europe-central.png
new file mode 100644
index 00000000..b980d381
Binary files /dev/null and b/heightmaps/europe-central.png differ
diff --git a/heightmaps/europe-north.png b/heightmaps/europe-north.png
new file mode 100644
index 00000000..e6c12014
Binary files /dev/null and b/heightmaps/europe-north.png differ
diff --git a/heightmaps/europe.png b/heightmaps/europe.png
new file mode 100644
index 00000000..3432fb6a
Binary files /dev/null and b/heightmaps/europe.png differ
diff --git a/heightmaps/greenland.png b/heightmaps/greenland.png
new file mode 100644
index 00000000..03d60464
Binary files /dev/null and b/heightmaps/greenland.png differ
diff --git a/heightmaps/hellenica.png b/heightmaps/hellenica.png
new file mode 100644
index 00000000..deb0258a
Binary files /dev/null and b/heightmaps/hellenica.png differ
diff --git a/heightmaps/iceland.png b/heightmaps/iceland.png
new file mode 100644
index 00000000..045f229d
Binary files /dev/null and b/heightmaps/iceland.png differ
diff --git a/heightmaps/import-rules.txt b/heightmaps/import-rules.txt
new file mode 100644
index 00000000..9478b35c
--- /dev/null
+++ b/heightmaps/import-rules.txt
@@ -0,0 +1,8 @@
+To get heightmap with correct height scale:
+1. Open tangrams.github.io
+2. Toggle off auto-exposure
+3. Set max elevation to 2000
+4. Set min elevation to -500
+5. Find region you like
+6. Render image
+7. Optionally rescale image to a smaller size (e.g. 500x300px) as high resolution is not used
\ No newline at end of file
diff --git a/heightmaps/indian-ocean.png b/heightmaps/indian-ocean.png
new file mode 100644
index 00000000..74ca8314
Binary files /dev/null and b/heightmaps/indian-ocean.png differ
diff --git a/heightmaps/mediterranean-sea.png b/heightmaps/mediterranean-sea.png
new file mode 100644
index 00000000..e296e7c7
Binary files /dev/null and b/heightmaps/mediterranean-sea.png differ
diff --git a/heightmaps/middle-east.png b/heightmaps/middle-east.png
new file mode 100644
index 00000000..57d03d4b
Binary files /dev/null and b/heightmaps/middle-east.png differ
diff --git a/heightmaps/north-america.png b/heightmaps/north-america.png
new file mode 100644
index 00000000..51b42ebc
Binary files /dev/null and b/heightmaps/north-america.png differ
diff --git a/heightmaps/us-centric.png b/heightmaps/us-centric.png
new file mode 100644
index 00000000..a73cbbe4
Binary files /dev/null and b/heightmaps/us-centric.png differ
diff --git a/heightmaps/us-mainland.png b/heightmaps/us-mainland.png
new file mode 100644
index 00000000..884f53c1
Binary files /dev/null and b/heightmaps/us-mainland.png differ
diff --git a/heightmaps/world-from-pacific.png b/heightmaps/world-from-pacific.png
new file mode 100644
index 00000000..3c7dbce5
Binary files /dev/null and b/heightmaps/world-from-pacific.png differ
diff --git a/heightmaps/world.png b/heightmaps/world.png
new file mode 100644
index 00000000..c54f4ab1
Binary files /dev/null and b/heightmaps/world.png differ
diff --git a/index.html b/index.html
index 517d69dd..653052e6 100644
--- a/index.html
+++ b/index.html
@@ -162,14 +162,14 @@
-
+
-
+
@@ -939,25 +939,52 @@
-
+
-
Map template
+
Heightmap
diff --git a/main.js b/main.js
index 713b5021..e6531488 100644
--- a/main.js
+++ b/main.js
@@ -2,7 +2,7 @@
// https://github.com/Azgaar/Fantasy-Map-Generator
"use strict";
-const version = "1.731"; // generator version
+const version = "1.732"; // generator version
document.title += " v" + version;
// switches to disable/enable logging features
@@ -192,15 +192,24 @@ if (!location.hostname) {
d3.select("#loading-text").transition().duration(1000).style("opacity", 0);
d3.select("#init-rose").transition().duration(4000).style("opacity", 0);
} else {
+ hideLoading();
checkLoadParameters();
+}
- // remove loading screen
- d3.select("#loading").transition().duration(4000).style("opacity", 0).remove();
- d3.select("#initial").transition().duration(4000).attr("opacity", 0).remove();
+function hideLoading() {
+ d3.select("#loading").transition().duration(4000).style("opacity", 0);
+ d3.select("#initial").transition().duration(4000).attr("opacity", 0);
d3.select("#optionsContainer").transition().duration(3000).style("opacity", 1);
d3.select("#tooltip").transition().duration(4000).style("opacity", 1);
}
+function showLoading() {
+ d3.select("#loading").transition().duration(200).style("opacity", 1);
+ d3.select("#initial").transition().duration(200).attr("opacity", 1);
+ d3.select("#optionsContainer").transition().duration(100).style("opacity", 0);
+ d3.select("#tooltip").transition().duration(200).style("opacity", 0);
+}
+
// decide which map should be loaded or generated on page load
function checkLoadParameters() {
const url = new URL(window.location.href);
@@ -253,7 +262,7 @@ function checkLoadParameters() {
async function generateMapOnLoad() {
await applyStyleOnLoad(); // apply previously selected default or custom style
- generate(); // generate map
+ await generate(); // generate map
focusOn(); // based on searchParams focus on point, cell or burg from MFCG
applyPreset(); // apply saved layers preset
}
@@ -437,6 +446,7 @@ function showWelcomeMessage() {
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version ${version}.
This version is compatible with ${changelog}, loaded .map files will be auto-updated.
Latest changes:
+
Pre-defined heightmaps
Advanced notes editor
Zones editor: filter by type
Color picker: new hatchings
@@ -632,7 +642,7 @@ void (function addDragToUpload() {
});
})();
-function generate() {
+async function generate() {
try {
const timeStart = performance.now();
invokeActiveZooming();
@@ -643,7 +653,7 @@ function generate() {
placePoints();
calculateVoronoi(grid, grid.points);
drawScaleBar();
- HeightmapGenerator.generate();
+ await HeightmapGenerator.generate();
markFeatures();
markupGridOcean();
addLakesInDeepDepressions();
@@ -929,6 +939,31 @@ function defineMapSize() {
function getSizeAndLatitude() {
const template = document.getElementById("templateInput").value; // heightmap template
+
+ if (template === "africa-centric") return [45, 53];
+ if (template === "arabia") return [20, 35];
+ if (template === "atlantics") return [42, 23];
+ if (template === "britain") return [7, 20];
+ if (template === "caribbean") return [15, 40];
+ if (template === "east-asia") return [11, 28];
+ if (template === "eurasia") return [38, 19];
+ if (template === "europe") return [20, 16];
+ if (template === "europe-accented") return [14, 22];
+ if (template === "europe-and-central-asia") return [25, 10];
+ if (template === "europe-central") return [11, 22];
+ if (template === "europe-north") return [7, 18];
+ if (template === "greenland") return [22, 7];
+ if (template === "hellenica") return [8, 27];
+ if (template === "iceland") return [2, 15];
+ if (template === "indian-ocean") return [45, 55];
+ if (template === "mediterranean-sea") return [10, 29];
+ if (template === "middle-east") return [8, 31];
+ if (template === "north-america") return [37, 17];
+ if (template === "us-centric") return [66, 27];
+ if (template === "us-mainland") return [16, 30];
+ if (template === "world") return [78, 27];
+ if (template === "world-from-pacific") return [75, 32];
+
const part = grid.features.some(f => f.land && f.border); // if land goes over map borders
const max = part ? 80 : 100; // max size
const lat = () => gauss(P(0.5) ? 40 : 60, 15, 25, 75); // latitude shift
@@ -1896,16 +1931,18 @@ function showStatistics() {
INFO && console.log(stats);
}
-const regenerateMap = debounce(function () {
+const regenerateMap = debounce(async function () {
WARN && console.warn("Generate new random map");
+ showLoading();
closeDialogs("#worldConfigurator, #options3d");
customization = 0;
- undraw();
resetZoom(1000);
- generate();
+ undraw();
+ await generate();
restoreLayers();
if (ThreeD.options.isOn) ThreeD.redraw();
if ($("#worldConfigurator").is(":visible")) editWorld();
+ hideLoading();
}, 1000);
// clear the map
diff --git a/modules/heightmap-generator.js b/modules/heightmap-generator.js
index a2567bfd..d8ee7634 100644
--- a/modules/heightmap-generator.js
+++ b/modules/heightmap-generator.js
@@ -3,13 +3,43 @@
window.HeightmapGenerator = (function () {
let cells, p;
- const generate = function () {
- TIME && console.time("generateHeightmap");
+ const generate = async function () {
cells = grid.cells;
p = grid.points;
cells.h = new Uint8Array(grid.points.length);
- const template = document.getElementById("templateInput").value;
+ const input = document.getElementById("templateInput");
+ const type = input.querySelector(`[value=${input.value}]`).parentElement.label;
+
+ if (type === "Specific") {
+ // pre-defined heightmap
+ TIME && console.time("defineHeightmap");
+ return new Promise(resolve => {
+ // create canvas where 1px correcponds to a cell
+ const canvas = document.createElement("canvas");
+ const ctx = canvas.getContext("2d");
+ const {cellsX, cellsY} = grid;
+ canvas.width = cellsX;
+ canvas.height = cellsY;
+
+ // load heightmap into image and render to canvas
+ const img = new Image();
+ img.src = `./heightmaps/${input.value}.png`;
+ img.onload = function () {
+ ctx.drawImage(img, 0, 0, cellsX, cellsY);
+ const imageData = ctx.getImageData(0, 0, cellsX, cellsY);
+ assignColorsToHeight(imageData.data);
+ canvas.remove();
+ img.remove();
+ TIME && console.timeEnd("defineHeightmap");
+ resolve();
+ };
+ });
+ }
+
+ // heightmap template
+ TIME && console.time("generateHeightmap");
+ const template = input.value;
const templateString = HeightmapTemplates[template];
const steps = templateString.split("\n");
@@ -79,8 +109,8 @@ window.HeightmapGenerator = (function () {
function addOneHill() {
const change = new Uint8Array(cells.h.length);
- let limit = 0,
- start;
+ let limit = 0;
+ let start;
let h = lim(getNumberInRange(height));
do {
@@ -410,5 +440,13 @@ window.HeightmapGenerator = (function () {
return rand(min * length, max * length);
}
+ function assignColorsToHeight(imageData) {
+ for (let i = 0; i < cells.i.length; i++) {
+ const lightness = imageData[i * 4] / 255;
+ const powered = lightness < 0.2 ? lightness : 0.2 + (lightness - 0.2) ** 0.8;
+ cells.h[i] = minmax(Math.floor(powered * 100), 0, 100);
+ }
+ }
+
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify};
})();
diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js
index b4ebde9f..43200d26 100644
--- a/modules/ui/heightmap-editor.js
+++ b/modules/ui/heightmap-editor.js
@@ -913,11 +913,9 @@ function editHeightmap() {
function uploadTemplate(dataLoaded) {
const steps = dataLoaded.split("\r\n");
- if (!steps.length) {
- tip("Cannot parse the template, please check the file", false, "error");
- return;
- }
+ if (!steps.length) return tip("Cannot parse the template, please check the file", false, "error");
templateBody.innerHTML = "";
+
for (const s of steps) {
const step = s.split(" ");
if (step.length !== 5) {
diff --git a/modules/ui/options.js b/modules/ui/options.js
index 74b214d5..37ebab80 100644
--- a/modules/ui/options.js
+++ b/modules/ui/options.js
@@ -306,10 +306,8 @@ function showSeedHistoryDialog() {
// generate map with historical seed
function restoreSeed(id) {
- if (mapHistory[id].seed == seed) {
- tip("The current map is already generated with this seed", null, "error");
- return;
- }
+ if (mapHistory[id].seed == seed) return tip("The current map is already generated with this seed", null, "error");
+
optionsSeed.value = mapHistory[id].seed;
mapWidthInput.value = mapHistory[id].width;
mapHeightInput.value = mapHistory[id].height;
@@ -547,7 +545,7 @@ function randomizeOptions() {
// 'Options' settings
if (randomize || !locked("template")) randomizeHeightmapTemplate();
- if (randomize || !locked("regions")) regionsInput.value = regionsOutput.value = gauss(15, 3, 2, 30);
+ if (randomize || !locked("regions")) regionsInput.value = regionsOutput.value = gauss(18, 5, 2, 30);
if (randomize || !locked("provinces")) provincesInput.value = provincesOutput.value = gauss(20, 10, 20, 100);
if (randomize || !locked("manors")) {
manorsInput.value = 1000;