diff --git a/index.html b/index.html index c0a4abc9..771a8ba0 100644 --- a/index.html +++ b/index.html @@ -824,6 +824,63 @@ + + + + + + + + + + Terracing + + + 0 + + + + + Reduce layers + + + 5 + + + + + Simplify line + + + 0 + + + + + Line style + + + + + + + Color scheme + + + + + + + Opacity @@ -1281,56 +1338,6 @@ - - - Terracing - - - 0 - - - - - Reduce layers - - - 5 - - - - - Simplify line - - - 0 - - - - - Line style - - - - - - - Color scheme - - - - - - - Fill opacity diff --git a/main.js b/main.js index c065fe51..eda779ec 100644 --- a/main.js +++ b/main.js @@ -604,6 +604,7 @@ void (function addDragToUpload() { async function generate(options) { try { + console.log("--- 1 ---", Math.random()); const timeStart = performance.now(); const {seed: precreatedSeed, graph: precreatedGraph} = options || {}; @@ -639,7 +640,9 @@ async function generate(options) { Biomes.define(); rankCells(); + console.log("--- 6 ---", Math.random()); Cultures.generate(); + console.log("--- 7 ---", Math.random()); Cultures.expand(); BurgsAndStates.generate(); Religions.generate(); @@ -722,10 +725,30 @@ function markFeatures() { grid.features = [0]; for (let i = 1, queue = [0]; queue[0] !== -1; i++) { + // [1864, 1731] + // if (queue[0] === 1864 || queue[0] === 1731) { + // cells.f[queue[0]] = 1; + // cells.t[queue[0]] = -1; + // queue = [cells.f.findIndex(f => !f)]; + // i--; + // continue; + // } + cells.f[queue[0]] = i; // feature number const land = heights[queue[0]] >= 20; let border = false; // true if feature touches map border + // if (i === 11) { + // debug + // .append("g") + // .attr("id", "feature11") + // .append("circle") + // .attr("cx", grid.points[queue[0]][0]) + // .attr("cy", grid.points[queue[0]][1]) + // .attr("r", 2) + // .attr("fill", "red"); + // } + while (queue.length) { const q = queue.pop(); if (cells.b[q]) border = true; @@ -859,6 +882,8 @@ function openNearSeaLakes() { } function removeLake(threshold, lake, ocean) { + debugger; + console.log("removeLake", threshold, lake, ocean); cells.h[threshold] = 19; cells.t[threshold] = -1; cells.f[threshold] = ocean; @@ -1349,22 +1374,14 @@ function drawCoastline() { // Re-mark features (ocean, lakes, islands) function reMarkFeatures() { TIME && console.time("reMarkFeatures"); - const cells = pack.cells, - features = (pack.features = [0]); + const cells = pack.cells; + const features = (pack.features = [0]); + cells.f = new Uint16Array(cells.i.length); // cell feature number cells.t = new Int8Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast; cells.haven = cells.i.length < 65535 ? new Uint16Array(cells.i.length) : new Uint32Array(cells.i.length); // cell haven (opposite water cell); cells.harbor = new Uint8Array(cells.i.length); // cell harbor (number of adjacent water cells); - const defineHaven = i => { - const water = cells.c[i].filter(c => cells.h[c] < 20); - const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2); - const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))]; - - cells.haven[i] = closest; - cells.harbor[i] = water.length; - }; - if (!cells.i.length) return; // no cells -> there is nothing to do for (let i = 1, queue = [0]; queue[0] !== -1; i++) { const start = queue[0]; // first cell @@ -1405,6 +1422,15 @@ function reMarkFeatures() { // markupPackLand markup(pack.cells, 3, 1, 0); + function defineHaven(i) { + const water = cells.c[i].filter(c => cells.h[c] < 20); + const dist2 = water.map(c => (cells.p[i][0] - cells.p[c][0]) ** 2 + (cells.p[i][1] - cells.p[c][1]) ** 2); + const closest = water[dist2.indexOf(Math.min.apply(Math, dist2))]; + + cells.haven[i] = closest; + cells.harbor[i] = water.length; + } + function defineOceanGroup(number) { if (number > grid.cells.i.length / 25) return "ocean"; if (number > grid.cells.i.length / 100) return "sea"; diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index cb4f6d05..a49bd872 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -54,6 +54,8 @@ window.Cultures = (function () { const colors = getColors(count); const emblemShape = document.getElementById("emblemShape").value; + console.log("--- c1 ---", Math.random()); + const codes = []; cultures.forEach(function (c, i) { @@ -71,28 +73,40 @@ window.Cultures = (function () { return; } - const cell = (c.center = placeCenter(c.sort ? c.sort : i => cells.s[i])); - centers.add(cells.p[cell]); + console.log(JSON.stringify(c, null, 2)); + console.log(Array.from(pack.cells.s).join()); + + const sortingFn = c.sort ? c.sort : i => cells.s[i]; + const center = placeCenter(sortingFn); + + console.log("--- c2-1 ---", i, Math.random()); + centers.add(cells.p[center]); + c.center = center; c.i = newId; delete c.odd; delete c.sort; c.color = colors[i]; - c.type = defineCultureType(cell); + console.log("--- c2-2 ---", i, Math.random()); + c.type = defineCultureType(center); + console.log("--- c2-3 ---", i, Math.random()); c.expansionism = defineCultureExpansionism(c.type); c.origins = [0]; c.code = abbreviate(c.name, codes); codes.push(c.code); - cultureIds[cell] = newId; + cultureIds[center] = newId; if (emblemShape === "random") c.shield = getRandomShield(); + console.log("--- c2-4 ---", i, Math.random()); }); + console.log("--- c3 ---", Math.random()); + cells.culture = cultureIds; - function placeCenter(v) { + function placeCenter(sortingFn) { let spacing = (graphWidth + graphHeight) / 2 / count; const MAX_ATTEMPTS = 100; - const sorted = [...populated].sort((a, b) => v(b) - v(a)); + const sorted = [...populated].sort((a, b) => sortingFn(b) - sortingFn(a)); const max = Math.floor(sorted.length / 2); let cellId = 0; diff --git a/modules/ui/layers.js b/modules/ui/layers.js index e20fe0cf..409f22e3 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -268,12 +268,14 @@ function drawHeightmap() { } } + return; + // render paths - for (const h of d3.range(0, 101)) { - const group = h < 20 ? ocean : land; + for (const height of d3.range(0, 101)) { + const group = height < 20 ? ocean : land; const scheme = getColorScheme(group.attr("scheme")); - if (h === 0 && renderOceanCells) { + if (height === 0 && renderOceanCells) { // draw base ocean layer group .append("rect") @@ -284,7 +286,7 @@ function drawHeightmap() { .attr("fill", scheme(1)); } - if (h === 20) { + if (height === 20) { // draw base land layer group .append("rect") @@ -295,21 +297,21 @@ function drawHeightmap() { .attr("fill", scheme(0.8)); } - if (paths[h] && paths[h].length >= 10) { + if (paths[height] && paths[height].length >= 10) { const curve = group.attr("curve") || "curveBasisClosed"; lineGen.curve(d3[curve]); - const terracing = group.attr("terracing") / 10 || 0; // shifted darker layer for pseudo-3d effect - const color = getColor(h, scheme); + const terracing = group.attr("terracing") / 10 || 0; + const color = getColor(height, scheme); - if (terracing && h >= 20) { - land + if (terracing) { + group .append("path") - .attr("d", paths[h]) + .attr("d", paths[height]) .attr("transform", "translate(.7,1.4)") .attr("fill", d3.color(color).darker(terracing)) - .attr("data-height", h); + .attr("data-height", height); } - group.append("path").attr("d", paths[h]).attr("fill", color).attr("data-height", h); + group.append("path").attr("d", paths[height]).attr("fill", color).attr("data-height", height); } } diff --git a/modules/ui/style.js b/modules/ui/style.js index 47b8be24..d9e8312f 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -31,6 +31,7 @@ function editStyle(element, group) { styleElementSelect.classList.add("glow"); if (group) styleGroupSelect.classList.add("glow"); + setTimeout(() => { styleElementSelect.classList.remove("glow"); if (group) styleGroupSelect.classList.remove("glow"); @@ -81,10 +82,10 @@ function selectStyleElement() { styleIsOff.style.display = isLayerOff ? "block" : "none"; // active group element - const group = styleGroupSelect.value; - if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(styleElement)) { - const gEl = group && el.select("#" + group); - el = group && gEl.size() ? gEl : el.select("g"); + if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) { + const group = styleGroupSelect.value; + const defaultGroupSelector = styleElement === "terrs" ? "#landHeights" : "g"; + el = group && el.select("#" + group).size() ? el.select("#" + group) : el.select(defaultGroupSelector); } // opacity @@ -170,11 +171,14 @@ function selectStyleElement() { if (styleElement === "terrs") { styleHeightmap.style.display = "block"; - styleHeightmapScheme.value = terrs.attr("scheme"); - styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = terrs.attr("terracing"); - styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = terrs.attr("skip"); - styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = terrs.attr("relax"); - styleHeightmapCurve.value = terrs.attr("curve"); + styleHeightmapRenderOceanOption.style.display = el.attr("id") === "oceanHeights" ? "block" : "none"; + styleHeightmapRenderOcean.checked = +el.attr("data-render"); + + styleHeightmapScheme.value = el.attr("scheme"); + styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = el.attr("terracing"); + styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = el.attr("skip"); + styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = el.attr("relax"); + styleHeightmapCurve.value = el.attr("curve"); } if (styleElement === "markers") { @@ -336,7 +340,7 @@ function selectStyleElement() { // update group options styleGroupSelect.options.length = 0; // remove all options - if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(styleElement)) { + if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) { const groups = byId(styleElement).querySelectorAll("g"); groups.forEach(el => { if (el.id === "burgLabels") return; @@ -519,18 +523,16 @@ outlineLayers.addEventListener("change", function () { }); styleHeightmapScheme.addEventListener("change", function () { - terrs.attr("scheme", this.value); + getEl().attr("scheme", this.value); drawHeightmap(); }); openCreateHeightmapSchemeButton.addEventListener("click", function () { // start with current scheme - this.dataset.stops = terrs.attr("scheme").startsWith("#") - ? terrs.attr("scheme") - : (function () { - const scheme = heightmapColorSchemes[terrs.attr("scheme")]; - return [0, 0.25, 0.5, 0.75, 1].map(scheme).map(toHEX).join(","); - })(); + const scheme = getEl().attr("scheme"); + this.dataset.stops = scheme.startsWith("#") + ? scheme + : (() => [0, 0.25, 0.5, 0.75, 1].map(heightmapColorSchemes[scheme]).map(toHEX).join(","))(); // render dialog base structure alertMessage.innerHTML = /* html */ `
@@ -622,7 +624,7 @@ openCreateHeightmapSchemeButton.addEventListener("click", function () { if (stops in heightmapColorSchemes) return tip("This scheme already exists", false, "error"); addCustomColorScheme(stops); - terrs.attr("scheme", stops); + getEl().attr("scheme", stops); drawHeightmap(); handleClose(); @@ -644,23 +646,28 @@ openCreateHeightmapSchemeButton.addEventListener("click", function () { }); }); +styleHeightmapRenderOcean.addEventListener("change", function () { + getEl().attr("data-render", +this.checked); + drawHeightmap(); +}); + styleHeightmapTerracingInput.addEventListener("input", function () { - terrs.attr("terracing", this.value); + getEl().attr("terracing", this.value); drawHeightmap(); }); styleHeightmapSkipInput.addEventListener("input", function () { - terrs.attr("skip", this.value); + getEl().attr("skip", this.value); drawHeightmap(); }); styleHeightmapSimplificationInput.addEventListener("input", function () { - terrs.attr("relax", this.value); + getEl().attr("relax", this.value); drawHeightmap(); }); styleHeightmapCurve.addEventListener("change", function () { - terrs.attr("curve", this.value); + getEl().attr("curve", this.value); drawHeightmap(); }); diff --git a/modules/ui/stylePresets.js b/modules/ui/stylePresets.js index 05302577..db0a6c03 100644 --- a/modules/ui/stylePresets.js +++ b/modules/ui/stylePresets.js @@ -239,7 +239,18 @@ function addStylePreset() { "#oceanLayers": ["filter", "layers"], "#oceanBase": ["fill"], "#oceanicPattern": ["href", "opacity"], - "#terrs": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"], + "#terrs #oceanHeights": [ + "data-render", + "opacity", + "scheme", + "terracing", + "skip", + "relax", + "curve", + "filter", + "mask" + ], + "#terrs #landHeights": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"], "#legend": [ "data-size", "font-size", diff --git a/utils/graphUtils.js b/utils/graphUtils.js index fdbe7bcb..99d3b52b 100644 --- a/utils/graphUtils.js +++ b/utils/graphUtils.js @@ -329,7 +329,7 @@ function drawCellsValue(data) { function drawPolygons(data) { const max = d3.max(data), min = d3.min(data), - scheme = getColorScheme(terrs.attr("scheme")); + scheme = getColorScheme(terrs.select("#landHeights").attr("scheme")); data = data.map(d => 1 - normalize(d, min, max)); debug.selectAll("polygon").remove(); @@ -338,7 +338,7 @@ function drawPolygons(data) { .data(data) .enter() .append("polygon") - .attr("points", (d, i) => getPackPolygon(i)) + .attr("points", (d, i) => getGridPolygon(i)) .attr("fill", d => scheme(d)) .attr("stroke", d => scheme(d)); }