diff --git a/index.css b/index.css index 05baf61c..c94d83ad 100644 --- a/index.css +++ b/index.css @@ -2309,11 +2309,8 @@ svg.button { #mapOverlay { position: absolute; + inset: 0; display: flex; - top: 0; - left: 0; - right: 0; - bottom: 0; align-items: center; justify-content: center; z-index: 10; diff --git a/index.html b/index.html index b5bae9ca..892120d5 100644 --- a/index.html +++ b/index.html @@ -24,29 +24,21 @@ font-size: 10px; overflow: hidden; } - #map { - position: absolute; + #loading > * { + pointer-events: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); } - #initial { + #loading > #loading-rose > use { fill: none; stroke: black; - pointer-events: none; - } - #init-rose { opacity: 0.7; transform-origin: center; - opacity: 0.7; - animation: 20s infinite spin; + animation: 20s linear 0s infinite spin; } - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(359deg); - } - } - #loading { + #loading > #loading-typography { opacity: 1; font-size: 11px; color: #fff5da; @@ -54,11 +46,6 @@ text-shadow: 0px 1px 4px #4c3a35; width: 80%; max-width: 600px; - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - pointer-events: none; } #loading-text { font-size: 1.8em; @@ -106,6 +93,14 @@ opacity: 0.1; } } + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } + } @@ -116,6 +111,7 @@ id="map" width="100%" height="100%" + style="position: absolute" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -267,18 +263,24 @@ - - - - -
-
Azgaar's
-
Fantasy Map Generator
-
v.
-

LOADING...

+ + + + + + + +
+
+
Azgaar's
+
Fantasy Map Generator
+
v.
+

LOADING...

+
+
diff --git a/main.js b/main.js index e1d59b56..cd5f0244 100644 --- a/main.js +++ b/main.js @@ -201,9 +201,6 @@ document.addEventListener("DOMContentLoaded", async () => { } } }); - - d3.select("#loading-text").transition().duration(1000).style("opacity", 0); - d3.select("#init-rose").transition().duration(4000).style("opacity", 0); } else { hideLoading(); await checkLoadParameters(); @@ -213,14 +210,12 @@ document.addEventListener("DOMContentLoaded", async () => { 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); } diff --git a/modules/dynamic/heightmap-selection.js b/modules/dynamic/heightmap-selection.js index 4dc631d7..3f38cf5d 100644 --- a/modules/dynamic/heightmap-selection.js +++ b/modules/dynamic/heightmap-selection.js @@ -89,10 +89,23 @@ function appendStyleSheet() { .heightmap-selection_container { display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); grid-gap: 8px; } + @media (max-width: 600px) { + .heightmap-selection_container { + grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); + grid-gap: 4px; + } + } + + @media (min-width: 2000px) { + .heightmap-selection_container { + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + } + } + .heightmap-selection article { padding: 4px; border-radius: 8px; @@ -128,13 +141,9 @@ function appendStyleSheet() { .heightmap-selection article > img { width: 100%; - aspect-ratio: 16/9; + aspect-ratio: ${graphWidth}/${graphHeight}; border-radius: 8px; - object-fit: cover; - } - - img.heightmap-selection_precreated { - filter: contrast(1.3); + object-fit: fill; } `; @@ -153,21 +162,23 @@ function insertEditorHtml() { const dataUrl = drawHeights(heights); return /* html */ `
- ${name} -
- ${name} - -
-
`; + ${name} +
+ ${name} + +
+ `; }) .join(""); const heightmapsHtml = heightmaps .map(({id, name}) => { + drawPrecreatedHeightmap(id); + return /* html */ `
- ${name} -
${name}
-
`; + ${name} +
${name}
+ `; }) .join(""); @@ -222,15 +233,19 @@ function drawHeights(heights) { canvas.height = grid.cellsY; const ctx = canvas.getContext("2d"); const imageData = ctx.createImageData(grid.cellsX, grid.cellsY); + const scheme = getColorScheme(); + const waterColor = scheme(1); - heights.forEach((height, i) => { - const h = height < 20 ? Math.max(height / 1.5, 0) : height; - const v = (h / 100) * 255; - imageData.data[i * 4] = v; - imageData.data[i * 4 + 1] = v; - imageData.data[i * 4 + 2] = v; - imageData.data[i * 4 + 3] = 255; - }); + for (let i = 0; i < heights.length; i++) { + const color = heights[i] < 20 ? waterColor : scheme(1 - heights[i] / 100); + const {r, g, b} = d3.color(color); + + const n = i * 4; + imageData.data[n] = r; + imageData.data[n + 1] = g; + imageData.data[n + 2] = b; + imageData.data[n + 3] = 255; + } ctx.putImageData(imageData, 0, 0); return canvas.toDataURL("image/png"); @@ -243,6 +258,13 @@ function generateHeightmap(id) { return heights; } +async function drawPrecreatedHeightmap(id) { + const heights = await HeightmapGenerator.fromPrecreated(id); + const dataUrl = drawHeights(heights); + const article = byId("heightmapSelection").querySelector(`[data-id="${id}"]`); + article.querySelector("img").src = dataUrl; +} + function regeneratePreview(article, id) { const seed = generateSeed(); article.dataset.seed = seed; diff --git a/modules/heightmap-generator.js b/modules/heightmap-generator.js index d8ec192d..71f2ea2d 100644 --- a/modules/heightmap-generator.js +++ b/modules/heightmap-generator.js @@ -24,7 +24,6 @@ window.HeightmapGenerator = (function () { const fromPrecreated = id => { return new Promise(resolve => { - TIME && console.time("defineHeightmap"); // create canvas where 1px corresponts to a cell const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); @@ -38,31 +37,26 @@ window.HeightmapGenerator = (function () { img.onload = () => { ctx.drawImage(img, 0, 0, cellsX, cellsY); const imageData = ctx.getImageData(0, 0, cellsX, cellsY); - assignColorsToHeight(imageData.data); + const heights = getHeightsFromImageData(imageData.data); canvas.remove(); img.remove(); - - grid.cells.h = heights; - cleanup(); - TIME && console.timeEnd("defineHeightmap"); - resolve(); + resolve(heights); }; }); }; const generate = async function () { Math.random = aleaPRNG(seed); - resetHeights(); - const id = byId("templateInput").value; - if (HeightmapTemplates[id]) { - TIME && console.time("generateHeightmap"); - grid.cells.h = fromTemplate(id); - cleanup(); - TIME && console.timeEnd("generateHeightmap"); - } else { - return fromPrecreated(id); - } + TIME && console.time("defineHeightmap"); + const id = byId("templateInput").value; + resetHeights(); + + const isTemplate = id in HeightmapTemplates; + grid.cells.h = isTemplate ? fromTemplate(id) : await fromPrecreated(id); + + cleanup(); + TIME && console.timeEnd("defineHeightmap"); }; function addStep(tool, a2, a3, a4, a5) { @@ -491,13 +485,32 @@ window.HeightmapGenerator = (function () { return rand(min * length, max * length); } - function assignColorsToHeight(imageData) { - for (let i = 0; i < grid.cells.i.length; i++) { + function getHeightsFromImageData(imageData) { + const heights = new Uint8Array(grid.points.length); + for (let i = 0; i < heights.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 heights; } - return {setHeights, resetHeights, getHeights, cleanup, generate, fromTemplate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask, invert}; + return { + setHeights, + resetHeights, + getHeights, + cleanup, + generate, + fromTemplate, + fromPrecreated, + addHill, + addRange, + addTrough, + addStrait, + addPit, + smooth, + modify, + mask, + invert + }; })(); diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 0ade51b7..f30004c1 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -1369,10 +1369,12 @@ function editHeightmap() { grid.cells.h.forEach((height, i) => { const h = height < 20 ? Math.max(height / 1.5, 0) : height; const v = (h / 100) * 255; - imageData.data[i * 4] = v; - imageData.data[i * 4 + 1] = v; - imageData.data[i * 4 + 2] = v; - imageData.data[i * 4 + 3] = 255; + + const n = i * 4; + imageData.data[n] = v; + imageData.data[n + 1] = v; + imageData.data[n + 2] = v; + imageData.data[n + 3] = 255; }); ctx.putImageData(imageData, 0, 0); diff --git a/modules/ui/layers.js b/modules/ui/layers.js index 3e53c2f2..9ff93af4 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -151,9 +151,9 @@ function toggleHeight(event) { function drawHeightmap() { TIME && console.time("drawHeightmap"); terrs.selectAll("*").remove(); - const cells = pack.cells, - vertices = pack.vertices, - n = cells.i.length; + + const {cells, vertices} = pack; + const n = cells.i.length; const used = new Uint8Array(cells.i.length); const paths = new Array(101).fill(""); @@ -161,6 +161,7 @@ function drawHeightmap() { const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect const skip = +terrs.attr("skip") + 1; const simplification = +terrs.attr("relax"); + switch (+terrs.attr("curve")) { case 0: lineGen.curve(d3.curveBasisClosed);