heightmap select - style fixes

This commit is contained in:
Azgaar 2022-05-27 02:22:25 +03:00
parent 6766de46ef
commit f56bd0f586
7 changed files with 123 additions and 91 deletions

View file

@ -2309,11 +2309,8 @@ svg.button {
#mapOverlay { #mapOverlay {
position: absolute; position: absolute;
inset: 0;
display: flex; display: flex;
top: 0;
left: 0;
right: 0;
bottom: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 10; z-index: 10;

View file

@ -24,29 +24,21 @@
font-size: 10px; font-size: 10px;
overflow: hidden; overflow: hidden;
} }
#map { #loading > * {
position: absolute; pointer-events: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
} }
#initial { #loading > #loading-rose > use {
fill: none; fill: none;
stroke: black; stroke: black;
pointer-events: none;
}
#init-rose {
opacity: 0.7; opacity: 0.7;
transform-origin: center; transform-origin: center;
opacity: 0.7; animation: 20s linear 0s infinite spin;
animation: 20s infinite spin;
} }
@keyframes spin { #loading > #loading-typography {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
#loading {
opacity: 1; opacity: 1;
font-size: 11px; font-size: 11px;
color: #fff5da; color: #fff5da;
@ -54,11 +46,6 @@
text-shadow: 0px 1px 4px #4c3a35; text-shadow: 0px 1px 4px #4c3a35;
width: 80%; width: 80%;
max-width: 600px; max-width: 600px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
} }
#loading-text { #loading-text {
font-size: 1.8em; font-size: 1.8em;
@ -106,6 +93,14 @@
opacity: 0.1; opacity: 0.1;
} }
} }
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
</style> </style>
<link rel="stylesheet" href="index.css?v=21052022" /> <link rel="stylesheet" href="index.css?v=21052022" />
<link rel="stylesheet" href="icons.css" /> <link rel="stylesheet" href="icons.css" />
@ -116,6 +111,7 @@
id="map" id="map"
width="100%" width="100%"
height="100%" height="100%"
style="position: absolute"
version="1.1" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
@ -267,19 +263,25 @@
</defs> </defs>
<g id="viewbox"></g> <g id="viewbox"></g>
<g id="scaleBar"></g> <g id="scaleBar"></g>
<g id="initial" opacity="1">
<rect x="-1%" y="-1%" width="102%" height="102%" fill="#466eab" />
<rect x="-1%" y="-1%" width="102%" height="102%" fill="url(#oceanic)" />
<use href="#rose" id="init-rose" x="50%" y="50%" />
</g>
</svg> </svg>
<div id="loading"> <div id="loading">
<svg width="100%" height="100%">
<rect x="-1%" y="-1%" width="102%" height="102%" fill="#466eab" />
<rect x="-1%" y="-1%" width="102%" height="102%" fill="url(#oceanic)" />
</svg>
<svg id="loading-rose" width="100%" height="100%" viewBox="0 0 700 700">
<use href="#rose" x="50%" y="50%" />
</svg>
<div id="loading-typography">
<div>
<div id="titleName"><t data-t="titleName">Azgaar's</t></div> <div id="titleName"><t data-t="titleName">Azgaar's</t></div>
<div id="title"><t data-t="title">Fantasy Map Generator</t></div> <div id="title"><t data-t="title">Fantasy Map Generator</t></div>
<div id="versionText"><t data-t="version">v. </t><span id="version"></span></div> <div id="versionText"><t data-t="version">v. </t><span id="version"></span></div>
<p id="loading-text"><t data-t="loading">LOADING</t><span>.</span><span>.</span><span>.</span></p> <p id="loading-text"><t data-t="loading">LOADING</t><span>.</span><span>.</span><span>.</span></p>
</div> </div>
</div>
</div>
<div id="optionsContainer" style="opacity: 0"> <div id="optionsContainer" style="opacity: 0">
<div id="collapsible"> <div id="collapsible">

View file

@ -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 { } else {
hideLoading(); hideLoading();
await checkLoadParameters(); await checkLoadParameters();
@ -213,14 +210,12 @@ document.addEventListener("DOMContentLoaded", async () => {
function hideLoading() { function hideLoading() {
d3.select("#loading").transition().duration(4000).style("opacity", 0); 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("#optionsContainer").transition().duration(3000).style("opacity", 1);
d3.select("#tooltip").transition().duration(4000).style("opacity", 1); d3.select("#tooltip").transition().duration(4000).style("opacity", 1);
} }
function showLoading() { function showLoading() {
d3.select("#loading").transition().duration(200).style("opacity", 1); 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("#optionsContainer").transition().duration(100).style("opacity", 0);
d3.select("#tooltip").transition().duration(200).style("opacity", 0); d3.select("#tooltip").transition().duration(200).style("opacity", 0);
} }

View file

@ -89,10 +89,23 @@ function appendStyleSheet() {
.heightmap-selection_container { .heightmap-selection_container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
grid-gap: 8px; 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 { .heightmap-selection article {
padding: 4px; padding: 4px;
border-radius: 8px; border-radius: 8px;
@ -128,13 +141,9 @@ function appendStyleSheet() {
.heightmap-selection article > img { .heightmap-selection article > img {
width: 100%; width: 100%;
aspect-ratio: 16/9; aspect-ratio: ${graphWidth}/${graphHeight};
border-radius: 8px; border-radius: 8px;
object-fit: cover; object-fit: fill;
}
img.heightmap-selection_precreated {
filter: contrast(1.3);
} }
`; `;
@ -164,8 +173,10 @@ function insertEditorHtml() {
const heightmapsHtml = heightmaps const heightmapsHtml = heightmaps
.map(({id, name}) => { .map(({id, name}) => {
drawPrecreatedHeightmap(id);
return /* html */ `<article data-id="${id}" data-seed="${seed}"> return /* html */ `<article data-id="${id}" data-seed="${seed}">
<img src="../../heightmaps/${id}.png" alt="${name}" class="heightmap-selection_precreated" /> <img alt="${name}" />
<div>${name}</div> <div>${name}</div>
</article>`; </article>`;
}) })
@ -222,15 +233,19 @@ function drawHeights(heights) {
canvas.height = grid.cellsY; canvas.height = grid.cellsY;
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(grid.cellsX, grid.cellsY); const imageData = ctx.createImageData(grid.cellsX, grid.cellsY);
const scheme = getColorScheme();
const waterColor = scheme(1);
heights.forEach((height, i) => { for (let i = 0; i < heights.length; i++) {
const h = height < 20 ? Math.max(height / 1.5, 0) : height; const color = heights[i] < 20 ? waterColor : scheme(1 - heights[i] / 100);
const v = (h / 100) * 255; const {r, g, b} = d3.color(color);
imageData.data[i * 4] = v;
imageData.data[i * 4 + 1] = v; const n = i * 4;
imageData.data[i * 4 + 2] = v; imageData.data[n] = r;
imageData.data[i * 4 + 3] = 255; imageData.data[n + 1] = g;
}); imageData.data[n + 2] = b;
imageData.data[n + 3] = 255;
}
ctx.putImageData(imageData, 0, 0); ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL("image/png"); return canvas.toDataURL("image/png");
@ -243,6 +258,13 @@ function generateHeightmap(id) {
return heights; 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) { function regeneratePreview(article, id) {
const seed = generateSeed(); const seed = generateSeed();
article.dataset.seed = seed; article.dataset.seed = seed;

View file

@ -24,7 +24,6 @@ window.HeightmapGenerator = (function () {
const fromPrecreated = id => { const fromPrecreated = id => {
return new Promise(resolve => { return new Promise(resolve => {
TIME && console.time("defineHeightmap");
// create canvas where 1px corresponts to a cell // create canvas where 1px corresponts to a cell
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
@ -38,31 +37,26 @@ window.HeightmapGenerator = (function () {
img.onload = () => { img.onload = () => {
ctx.drawImage(img, 0, 0, cellsX, cellsY); ctx.drawImage(img, 0, 0, cellsX, cellsY);
const imageData = ctx.getImageData(0, 0, cellsX, cellsY); const imageData = ctx.getImageData(0, 0, cellsX, cellsY);
assignColorsToHeight(imageData.data); const heights = getHeightsFromImageData(imageData.data);
canvas.remove(); canvas.remove();
img.remove(); img.remove();
resolve(heights);
grid.cells.h = heights;
cleanup();
TIME && console.timeEnd("defineHeightmap");
resolve();
}; };
}); });
}; };
const generate = async function () { const generate = async function () {
Math.random = aleaPRNG(seed); Math.random = aleaPRNG(seed);
resetHeights();
const id = byId("templateInput").value;
if (HeightmapTemplates[id]) { TIME && console.time("defineHeightmap");
TIME && console.time("generateHeightmap"); const id = byId("templateInput").value;
grid.cells.h = fromTemplate(id); resetHeights();
const isTemplate = id in HeightmapTemplates;
grid.cells.h = isTemplate ? fromTemplate(id) : await fromPrecreated(id);
cleanup(); cleanup();
TIME && console.timeEnd("generateHeightmap"); TIME && console.timeEnd("defineHeightmap");
} else {
return fromPrecreated(id);
}
}; };
function addStep(tool, a2, a3, a4, a5) { function addStep(tool, a2, a3, a4, a5) {
@ -491,13 +485,32 @@ window.HeightmapGenerator = (function () {
return rand(min * length, max * length); return rand(min * length, max * length);
} }
function assignColorsToHeight(imageData) { function getHeightsFromImageData(imageData) {
for (let i = 0; i < grid.cells.i.length; i++) { const heights = new Uint8Array(grid.points.length);
for (let i = 0; i < heights.length; i++) {
const lightness = imageData[i * 4] / 255; const lightness = imageData[i * 4] / 255;
const powered = lightness < 0.2 ? lightness : 0.2 + (lightness - 0.2) ** 0.8; const powered = lightness < 0.2 ? lightness : 0.2 + (lightness - 0.2) ** 0.8;
heights[i] = minmax(Math.floor(powered * 100), 0, 100); 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
};
})(); })();

View file

@ -1369,10 +1369,12 @@ function editHeightmap() {
grid.cells.h.forEach((height, i) => { grid.cells.h.forEach((height, i) => {
const h = height < 20 ? Math.max(height / 1.5, 0) : height; const h = height < 20 ? Math.max(height / 1.5, 0) : height;
const v = (h / 100) * 255; const v = (h / 100) * 255;
imageData.data[i * 4] = v;
imageData.data[i * 4 + 1] = v; const n = i * 4;
imageData.data[i * 4 + 2] = v; imageData.data[n] = v;
imageData.data[i * 4 + 3] = 255; imageData.data[n + 1] = v;
imageData.data[n + 2] = v;
imageData.data[n + 3] = 255;
}); });
ctx.putImageData(imageData, 0, 0); ctx.putImageData(imageData, 0, 0);

View file

@ -151,9 +151,9 @@ function toggleHeight(event) {
function drawHeightmap() { function drawHeightmap() {
TIME && console.time("drawHeightmap"); TIME && console.time("drawHeightmap");
terrs.selectAll("*").remove(); terrs.selectAll("*").remove();
const cells = pack.cells,
vertices = pack.vertices, const {cells, vertices} = pack;
n = cells.i.length; const n = cells.i.length;
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const paths = new Array(101).fill(""); 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 terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect
const skip = +terrs.attr("skip") + 1; const skip = +terrs.attr("skip") + 1;
const simplification = +terrs.attr("relax"); const simplification = +terrs.attr("relax");
switch (+terrs.attr("curve")) { switch (+terrs.attr("curve")) {
case 0: case 0:
lineGen.curve(d3.curveBasisClosed); lineGen.curve(d3.curveBasisClosed);