mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
commit
b144191621
6 changed files with 375 additions and 273 deletions
|
|
@ -922,7 +922,7 @@ fieldset {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
body button.noicon {
|
||||
#templateTools > button {
|
||||
width: 1.8em;
|
||||
height: 1.6em;
|
||||
margin: 1px;
|
||||
|
|
|
|||
45
index.html
45
index.html
|
|
@ -107,7 +107,7 @@
|
|||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="index.css?v=18052022" />
|
||||
<link rel="stylesheet" href="index.css?v=21052022" />
|
||||
<link rel="stylesheet" href="icons.css" />
|
||||
<link rel="stylesheet" href="libs/jquery-ui.css" />
|
||||
</head>
|
||||
|
|
@ -1292,7 +1292,7 @@
|
|||
<option value="volcano">Volcano</option>
|
||||
<option value="highIsland">High Island</option>
|
||||
<option value="lowIsland">Low Island</option>
|
||||
<option value="continents">Two Continents</option>
|
||||
<option value="continents">Continents</option>
|
||||
<option value="archipelago">Archipelago</option>
|
||||
<option value="atoll">Atoll</option>
|
||||
<option value="mediterranean">Mediterranean</option>
|
||||
|
|
@ -1302,6 +1302,7 @@
|
|||
<option value="shattered">Shattered</option>
|
||||
<option value="taklamakan">Taklamakan</option>
|
||||
<option value="oldWorld">Old World</option>
|
||||
<option value="fractious">Fractious</option>
|
||||
</optgroup>
|
||||
<optgroup label="Specific">
|
||||
<option value="africa-centric">Africa Centric</option>
|
||||
|
|
@ -1758,13 +1759,13 @@
|
|||
<label for="allowErosion" class="checkbox-label">Allow water erosion</label>
|
||||
</div>
|
||||
<div data-tip="Maximum number of iterations taken to resolve depressions. Increase if you have rivers ending nowhere">
|
||||
Depressions filling max iterations:
|
||||
<div>Depressions filling max iterations:</div>
|
||||
<input id="resolveDepressionsStepsInput" data-stored="resolveDepressionsSteps" type="range" min="0" max="500" value="250" />
|
||||
<input id="resolveDepressionsStepsOutput" data-stored="resolveDepressionsSteps" type="number" min="0" max="1000" value="250" />
|
||||
</div>
|
||||
|
||||
<div data-tip="Depression depth to form a new lake. Increase to reduce number of lakes added by system">
|
||||
Depression depth threshold:
|
||||
<div>Depression depth threshold:</div>
|
||||
<input id="lakeElevationLimitInput" data-stored="lakeElevationLimit" type="range" min="0" max="80" value="20" />
|
||||
<input id="lakeElevationLimitOutput" data-stored="lakeElevationLimit" type="number" min="0" max="80" value="20" />
|
||||
</div>
|
||||
|
|
@ -2932,13 +2933,13 @@
|
|||
|
||||
<div id="templateEditor" class="dialog stable" style="display: none">
|
||||
<div id="templateTop">
|
||||
<i>Select template: </i
|
||||
><select id="templateSelect" style="width: 16em" data-prev="templateCustom" data-tip="Select base template">
|
||||
<i>Select template: </i>
|
||||
<select id="templateSelect" style="width: 16em" data-prev="templateCustom" data-tip="Select base template">
|
||||
<option value="custom" selected>Custom</option>
|
||||
<option value="volcano">Volcano</option>
|
||||
<option value="highIsland">High Island</option>
|
||||
<option value="lowIsland">Low Island</option>
|
||||
<option value="continents">Two Continents</option>
|
||||
<option value="continents">Continents</option>
|
||||
<option value="archipelago">Archipelago</option>
|
||||
<option value="atoll">Atoll</option>
|
||||
<option value="mediterranean">Mediterranean</option>
|
||||
|
|
@ -2948,17 +2949,20 @@
|
|||
<option value="shattered">Shattered</option>
|
||||
<option value="taklamakan">Taklamakan</option>
|
||||
<option value="oldWorld">Old World</option>
|
||||
<option value="fractious">Fractious</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="templateTools">
|
||||
<button id="templateHill" data-tip="Hill: small blob" class="noicon">H</button>
|
||||
<button id="templatePit" data-tip="Pit: round depression" class="noicon">P</button>
|
||||
<button id="templateRange" data-tip="Range: elongated elevation" class="noicon">R</button>
|
||||
<button id="templateTrough" data-tip="Trough: elongated depression" class="noicon">T</button>
|
||||
<button id="templateStrait" data-tip="Strait: centered vertical or horizontal depression" class="noicon">S</button>
|
||||
<button id="templateAdd" data-tip="Add or subtract value from all heights in range" class="noicon">+</button>
|
||||
<button id="templateMultiply" data-tip="Multiply all heights in range by factor" class="noicon">*</button>
|
||||
<button id="templateSmooth" data-tip="Smooth the map replacing cell heights by an average values of its neighbors" class="noicon">~</button>
|
||||
<button data-type="Hill" data-tip="Hill: small blob">H</button>
|
||||
<button data-type="Pit" data-tip="Pit: round depression">P</button>
|
||||
<button data-type="Range" data-tip="Range: elongated elevation">R</button>
|
||||
<button data-type="Trough" data-tip="Trough: elongated depression">T</button>
|
||||
<button data-type="Strait" data-tip="Strait: centered vertical or horizontal depression">S</button>
|
||||
<button data-type="Mask" data-tip="Mask: lower cells near edges or in map center">M</button>
|
||||
<button data-type="Invert" data-tip="Invert heightmap along the axes">I</button>
|
||||
<button data-type="Add" data-tip="Add or subtract value from all heights in range">+</button>
|
||||
<button data-type="Multiply" data-tip="Multiply all heights in range by factor">*</button>
|
||||
<button data-type="Smooth" data-tip="Smooth the map replacing cell heights by an average values of its neighbors">~</button>
|
||||
</div>
|
||||
<div id="templateBody" data-changed="0" class="table" style="padding: 2px 0">
|
||||
<div data-type="Hill">
|
||||
|
|
@ -2973,7 +2977,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="templateBottom">
|
||||
<button id="templateRun" data-tip="Apply current template" class="icon-play-circled2"></button>
|
||||
<button id="templateRun" data-tip="Execute the template" class="icon-play-circled2"></button>
|
||||
<button id="templateUndo" data-tip="Undo the latest action" class="icon-ccw" disabled></button>
|
||||
<button id="templateRedo" data-tip="Redo the action" class="icon-cw" disabled></button>
|
||||
<button id="templateSave" data-tip="Download the template as a text file" class="icon-download"></button>
|
||||
|
|
@ -2985,6 +2989,9 @@
|
|||
onclick="openURL('https://cartographyassets.com/asset-category/specific-assets/azgaars-generator/templates')"
|
||||
></button>
|
||||
<button id="templateTutorial" data-tip="Open Template Editor Tutorial" class="icon-info" onclick="wiki('Heightmap-template-editor')"></button>
|
||||
<label data-tip="Set seed if you want template to generate the same heightmap each time. Leave blank to use random seed">
|
||||
Seed: <input id="templateSeed" value="" type="number" min="1" max="999999999" step="1" style="width: 7em" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -6109,8 +6116,8 @@
|
|||
<script src="utils/unitUtils.js"></script>
|
||||
|
||||
<script src="modules/voronoi.js"></script>
|
||||
<script src="modules/heightmap-templates.js"></script>
|
||||
<script src="modules/heightmap-generator.js"></script>
|
||||
<script src="modules/heightmap-templates.js?v=21052020"></script>
|
||||
<script src="modules/heightmap-generator.js?v=21052020"></script>
|
||||
<script src="modules/ocean-layers.js"></script>
|
||||
<script src="modules/river-generator.js"></script>
|
||||
<script src="modules/lakes.js"></script>
|
||||
|
|
@ -6140,7 +6147,7 @@
|
|||
<script defer src="modules/ui/editors.js?v=18052022"></script>
|
||||
<script defer src="modules/ui/tools.js"></script>
|
||||
<script defer src="modules/ui/world-configurator.js"></script>
|
||||
<script defer src="modules/ui/heightmap-editor.js"></script>
|
||||
<script defer src="modules/ui/heightmap-editor.js?v=21052020"></script>
|
||||
<script defer src="modules/ui/provinces-editor.js?v=19052022"></script>
|
||||
<script defer src="modules/ui/biomes-editor.js?v=18052022"></script>
|
||||
<script defer src="modules/ui/namesbase-editor.js"></script>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ window.HeightmapGenerator = (function () {
|
|||
// load heightmap into image and render to canvas
|
||||
const img = new Image();
|
||||
img.src = `./heightmaps/${input.value}.png`;
|
||||
img.onload = function () {
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 0, 0, cellsX, cellsY);
|
||||
const imageData = ctx.getImageData(0, 0, cellsX, cellsY);
|
||||
assignColorsToHeight(imageData.data);
|
||||
|
|
@ -61,6 +61,7 @@ window.HeightmapGenerator = (function () {
|
|||
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);
|
||||
|
|
@ -100,7 +101,7 @@ window.HeightmapGenerator = (function () {
|
|||
if (cells === 100000) return 0.93;
|
||||
}
|
||||
|
||||
const addHill = function (count, height, rangeX, rangeY) {
|
||||
const addHill = (count, height, rangeX, rangeY) => {
|
||||
count = getNumberInRange(count);
|
||||
const power = getBlobPower();
|
||||
while (count > 0) {
|
||||
|
|
@ -137,7 +138,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
const addPit = function (count, height, rangeX, rangeY) {
|
||||
const addPit = (count, height, rangeX, rangeY) => {
|
||||
count = getNumberInRange(count);
|
||||
while (count > 0) {
|
||||
addOnePit();
|
||||
|
|
@ -173,7 +174,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
const addRange = function (count, height, rangeX, rangeY) {
|
||||
const addRange = (count, height, rangeX, rangeY) => {
|
||||
count = getNumberInRange(count);
|
||||
const power = getLinePower();
|
||||
while (count > 0) {
|
||||
|
|
@ -259,7 +260,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
const addTrough = function (count, height, rangeX, rangeY) {
|
||||
const addTrough = (count, height, rangeX, rangeY) => {
|
||||
count = getNumberInRange(count);
|
||||
const power = getLinePower();
|
||||
while (count > 0) {
|
||||
|
|
@ -354,7 +355,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
const addStrait = function (width, direction = "vertical") {
|
||||
const addStrait = (width, direction = "vertical") => {
|
||||
width = Math.min(getNumberInRange(width), grid.cellsX / 3);
|
||||
if (width < 1 && P(width)) return;
|
||||
const used = new Uint8Array(cells.h.length);
|
||||
|
|
@ -364,8 +365,8 @@ window.HeightmapGenerator = (function () {
|
|||
const endX = vert ? Math.floor(graphWidth - startX - graphWidth * 0.1 + Math.random() * graphWidth * 0.2) : graphWidth - 5;
|
||||
const endY = vert ? graphHeight - 5 : Math.floor(graphHeight - startY - graphHeight * 0.1 + Math.random() * graphHeight * 0.2);
|
||||
|
||||
const start = findGridCell(startX, startY),
|
||||
end = findGridCell(endX, endY);
|
||||
const start = findGridCell(startX, startY);
|
||||
const end = findGridCell(endX, endY);
|
||||
let range = getRange(start, end);
|
||||
const query = [];
|
||||
|
||||
|
|
@ -407,7 +408,7 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
const modify = function (range, add, mult, power) {
|
||||
const modify = (range, add, mult, power) => {
|
||||
const min = range === "land" ? 20 : range === "all" ? 0 : +range.split("-")[0];
|
||||
const max = range === "land" || range === "all" ? 100 : +range.split("-")[1];
|
||||
const isLand = min === 20;
|
||||
|
|
@ -422,14 +423,49 @@ window.HeightmapGenerator = (function () {
|
|||
});
|
||||
};
|
||||
|
||||
const smooth = function (fr = 2, add = 0) {
|
||||
const smooth = (fr = 2, add = 0) => {
|
||||
cells.h = cells.h.map((h, i) => {
|
||||
const a = [h];
|
||||
cells.c[i].forEach(c => a.push(cells.h[c]));
|
||||
if (fr === 1) return d3.mean(a) + add;
|
||||
return lim((h * (fr - 1) + d3.mean(a) + add) / fr);
|
||||
});
|
||||
};
|
||||
|
||||
const mask = (power = 1) => {
|
||||
const fr = power ? Math.abs(power) : 1;
|
||||
|
||||
cells.h = cells.h.map((h, i) => {
|
||||
const [x, y] = p[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
|
||||
if (power < 0) distance = 1 - distance; // inverted, 0 is center, 1 is edge
|
||||
const masked = h * distance;
|
||||
return lim((h * (fr - 1) + masked) / fr);
|
||||
});
|
||||
};
|
||||
|
||||
const invert = (count, axes) => {
|
||||
if (!P(count)) return;
|
||||
|
||||
const invertX = axes !== "y";
|
||||
const invertY = axes !== "x";
|
||||
const {cellsX, cellsY} = grid;
|
||||
|
||||
const inverted = cells.h.map((h, i) => {
|
||||
const x = i % cellsX;
|
||||
const y = Math.floor(i / cellsX);
|
||||
|
||||
const nx = invertX ? cellsX - x - 1 : x;
|
||||
const ny = invertY ? cellsY - y - 1 : y;
|
||||
const invertedI = nx + ny * cellsX;
|
||||
return cells.h[invertedI];
|
||||
});
|
||||
|
||||
cells.h = inverted;
|
||||
};
|
||||
|
||||
function getPointInRange(range, length) {
|
||||
if (typeof range !== "string") {
|
||||
ERROR && console.error("Range should be a string");
|
||||
|
|
@ -449,5 +485,5 @@ window.HeightmapGenerator = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify};
|
||||
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify, mask, invert};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -4,49 +4,55 @@ window.HeightmapTemplates = (function () {
|
|||
const volcano = `Hill 1 90-100 44-56 40-60
|
||||
Multiply 0.8 50-100 0 0
|
||||
Range 1.5 30-55 45-55 40-60
|
||||
Smooth 2 0 0 0
|
||||
Hill 1.5 25-35 25-30 20-75
|
||||
Hill 1 25-35 75-80 25-75
|
||||
Hill 0.5 20-25 10-15 20-25`;
|
||||
Smooth 3 0 0 0
|
||||
Hill 1.5 35-45 25-30 20-75
|
||||
Hill 1 35-55 75-80 25-75
|
||||
Hill 0.5 20-25 10-15 20-25
|
||||
Mask 3 0 0 0`;
|
||||
|
||||
const highIsland = `Hill 1 90-100 65-75 47-53
|
||||
Add 5 all 0 0
|
||||
Hill 6 20-23 25-55 45-55
|
||||
Add 7 all 0 0
|
||||
Hill 5-6 20-30 25-55 45-55
|
||||
Range 1 40-50 45-55 45-55
|
||||
Multiply 0.8 land 0 0
|
||||
Mask 3 0 0 0
|
||||
Smooth 2 0 0 0
|
||||
Trough 2-3 20-30 20-30 20-30
|
||||
Trough 2-3 20-30 60-80 70-80
|
||||
Hill 1 10-15 60-60 50-50
|
||||
Hill 1.5 13-16 15-20 20-75
|
||||
Multiply 0.8 20-100 0 0
|
||||
Range 1.5 30-40 15-85 30-40
|
||||
Range 1.5 30-40 15-85 60-70
|
||||
Pit 2-3 10-15 15-85 20-80`;
|
||||
Pit 3-5 10-30 15-85 20-80`;
|
||||
|
||||
const lowIsland = `Hill 1 90-99 60-80 45-55
|
||||
Hill 4-5 25-35 20-65 40-60
|
||||
Hill 1-2 20-30 10-30 10-90
|
||||
Smooth 2 0 0 0
|
||||
Hill 6-7 25-35 20-70 30-70
|
||||
Range 1 40-50 45-55 45-55
|
||||
Smooth 3 0 0 0
|
||||
Trough 1.5 20-30 15-85 20-30
|
||||
Trough 1.5 20-30 15-85 70-80
|
||||
Trough 2-3 20-30 15-85 20-30
|
||||
Trough 2-3 20-30 15-85 70-80
|
||||
Hill 1.5 10-15 5-15 20-80
|
||||
Hill 1 10-15 85-95 70-80
|
||||
Pit 3-5 10-15 15-85 20-80
|
||||
Multiply 0.4 20-100 0 0`;
|
||||
Pit 5-7 15-25 15-85 20-80
|
||||
Multiply 0.4 20-100 0 0
|
||||
Mask 4 0 0 0`;
|
||||
|
||||
const continents = `Hill 1 80-85 75-80 40-60
|
||||
Hill 1 80-85 20-25 40-60
|
||||
Multiply 0.22 20-100 0 0
|
||||
Hill 5-6 15-20 25-75 20-82
|
||||
Range .8 30-60 5-15 20-45
|
||||
Range .8 30-60 5-15 55-80
|
||||
const continents = `Hill 1 80-85 60-80 40-60
|
||||
Hill 1 80-85 20-30 40-60
|
||||
Hill 6-7 15-30 25-75 15-85
|
||||
Multiply 0.6 land 0 0
|
||||
Hill 8-10 5-10 15-85 20-80
|
||||
Range 1-2 30-60 5-15 25-75
|
||||
Range 1-2 30-60 80-95 25-75
|
||||
Range 0-3 30-60 80-90 20-80
|
||||
Trough 3-4 15-20 15-85 20-80
|
||||
Strait 2 vertical 0 0
|
||||
Smooth 2 0 0 0
|
||||
Trough 1-2 5-10 45-55 45-55
|
||||
Pit 3-4 10-15 15-85 20-80
|
||||
Hill 1 5-10 40-60 40-60`;
|
||||
Strait 1 vertical 0 0
|
||||
Smooth 3 0 0 0
|
||||
Trough 3-4 15-20 15-85 20-80
|
||||
Trough 3-4 5-10 45-55 45-55
|
||||
Pit 3-4 10-20 15-85 20-80
|
||||
Mask 4 0 0 0`;
|
||||
|
||||
const archipelago = `Add 11 all 0 0
|
||||
Range 2-3 40-60 20-80 20-80
|
||||
|
|
@ -63,18 +69,19 @@ window.HeightmapTemplates = (function () {
|
|||
Hill .5 30-50 25-35 30-70
|
||||
Smooth 1 0 0 0
|
||||
Multiply 0.2 25-100 0 0
|
||||
Hill .5 10-20 50-55 48-52`;
|
||||
Hill 0.5 10-20 50-55 48-52`;
|
||||
|
||||
const mediterranean = `Range 3-4 30-50 0-100 0-10
|
||||
Range 3-4 30-50 0-100 90-100
|
||||
Hill 5-6 30-70 0-100 0-5
|
||||
Hill 5-6 30-70 0-100 95-100
|
||||
const mediterranean = `Range 4-6 30-80 0-100 0-10
|
||||
Range 4-6 30-80 0-100 90-100
|
||||
Hill 6-8 30-50 10-90 0-5
|
||||
Hill 6-8 30-50 10-90 95-100
|
||||
Multiply 0.9 land 0 0
|
||||
Mask -2 0 0 0
|
||||
Smooth 1 0 0 0
|
||||
Hill 2-3 30-70 0-5 20-80
|
||||
Hill 2-3 30-70 95-100 20-80
|
||||
Multiply 0.8 land 0 0
|
||||
Trough 3-5 40-50 0-100 0-10
|
||||
Trough 3-5 40-50 0-100 90-100`;
|
||||
Trough 3-6 40-50 0-100 0-10
|
||||
Trough 3-6 40-50 0-100 90-100`;
|
||||
|
||||
const peninsula = `Range 2-3 20-35 40-50 0-15
|
||||
Add 5 all 0 0
|
||||
|
|
@ -83,7 +90,8 @@ window.HeightmapTemplates = (function () {
|
|||
Hill 3-4 3-5 5-95 80-100
|
||||
Hill 1-2 3-5 5-95 40-60
|
||||
Trough 5-6 10-25 5-95 5-95
|
||||
Smooth 3 0 0 0`;
|
||||
Smooth 3 0 0 0
|
||||
Invert 0.4 both 0 0`;
|
||||
|
||||
const pangea = `Hill 1-2 25-40 15-50 0-10
|
||||
Hill 1-2 5-40 50-85 0-10
|
||||
|
|
@ -106,7 +114,8 @@ window.HeightmapTemplates = (function () {
|
|||
Trough 4-8 15-30 10-50 20-40
|
||||
Trough 4-8 15-30 30-70 40-60
|
||||
Trough 4-8 15-30 50-90 60-80
|
||||
Trough 4-8 15-30 70-100 80-100`;
|
||||
Trough 4-8 15-30 70-100 80-100
|
||||
Invert 0.25 x 0 0`;
|
||||
|
||||
const shattered = `Hill 8 35-40 15-85 30-70
|
||||
Trough 10-20 40-50 5-95 5-95
|
||||
|
|
@ -117,58 +126,42 @@ window.HeightmapTemplates = (function () {
|
|||
Hill 2-4 60-85 0-5 0-100
|
||||
Hill 2-4 60-85 95-100 0-100
|
||||
Hill 3-4 60-85 20-80 0-5
|
||||
Hill 3-4 60-85 20-80 95-100`;
|
||||
Hill 3-4 60-85 20-80 95-100
|
||||
Smooth 3 0 0 0`;
|
||||
|
||||
|
||||
const oldWorld = `Hill 4-6 20-40 15-85 30-45
|
||||
Hill 3-7 20-40 15-85 55-70
|
||||
Strait 2-7 vertical 0 0
|
||||
Pit 1-2 40-50 35-55 20-80
|
||||
Strait 2-7 vertical 0 0
|
||||
Range 2-3 20-25 15-35 20-30
|
||||
Range 2-3 20-25 15-35 65-80
|
||||
Range 2-3 20-25 45-85 20-45
|
||||
Range 2-3 20-25 45-85 65-80
|
||||
Multiply .9 80-100 0 0
|
||||
Strait 2-7 vertical 0 0
|
||||
Pit 2-3 40-50 45-65 20-80
|
||||
Trough 1-2 40-50 15-45 20-45
|
||||
Trough 1-3 40-50 15-45 45-80
|
||||
Trough 1-2 40-50 45-85 20-45
|
||||
Trough 1-2 40-50 45-85 45-80
|
||||
Multiply 1.2 17-20 0 0
|
||||
Strait 2-7 horizontal 0 0
|
||||
Multiply 1.2 17-50 0 0
|
||||
Range 1-2 20-25 15-45 45-65
|
||||
Range 1-2 20-25 65-85 45-80
|
||||
Multiply 1.1 50-80 0 0
|
||||
Hill 1-2 20 15-45 20-80
|
||||
Hill 1-2 20 65-85 20-80
|
||||
Multiply 1.2 15-30 0 0
|
||||
Strait 2-7 vertical 0 0
|
||||
Trough 1-2 40-50 35-65 65-80
|
||||
Range 1-2 20-25 15-35 20-45
|
||||
Strait 2-7 vertical 0 0
|
||||
Range 1-2 20-25 65-85 45-80
|
||||
Multiply .9 70-100 0 0
|
||||
Hill 1-2 20-25 15-45 65-80
|
||||
Hill 1-2 20-25 65-85 20-45
|
||||
Hill 1 20-25 15-45 45-65
|
||||
Hill 1 20-25 65-85 45-65
|
||||
Strait 2-7 vertical 0 0
|
||||
Trough 1-2 20-50 15-45 45-65
|
||||
Trough 1-2 20-50 65-85 45-65
|
||||
Strait 2-7 horizontal 0 0
|
||||
Multiply 0.8 70-100 0 0
|
||||
Hill 1-2 20-25 35-45 45-65
|
||||
Hill 1-2 20-25 65-70 45-65
|
||||
Pit 2-3 40-50 45-65 30-70
|
||||
Trough 1-2 40-50 15-85 65-80
|
||||
Trough 1-2 40-50 15-85 10-35
|
||||
Strait 2-5 vertical 0 0
|
||||
Multiply 1.1 45-90 0 0
|
||||
const oldWorld = `Range 3 70 15-85 20-80
|
||||
Hill 2-3 50-70 15-45 20-80
|
||||
Hill 2-3 50-70 65-85 20-80
|
||||
Hill 4-6 20-25 15-85 20-80
|
||||
Multiply 0.5 land 0 0
|
||||
Smooth 2 0 0 0
|
||||
Range 3-4 20-50 15-35 20-45
|
||||
Range 2-4 20-50 65-85 45-80
|
||||
Strait 3-7 vertical 0 0
|
||||
Trough 1-2 40-50 45-65 45-65`;
|
||||
Trough 6-8 20-50 15-85 45-65
|
||||
Pit 5-6 20-30 10-90 10-90`;
|
||||
|
||||
return {volcano, highIsland, lowIsland, continents, archipelago, atoll, mediterranean, peninsula, peninsula, pangea, isthmus, shattered, taklamakan, oldWorld};
|
||||
const fractious = `Hill 12-15 50-80 5-95 5-95
|
||||
Mask -1.5 0 0 0
|
||||
Mask 3 0 0 0
|
||||
Add -20 30-100 0 0
|
||||
Range 6-8 40-50 5-95 10-90`;
|
||||
|
||||
return {
|
||||
volcano,
|
||||
highIsland,
|
||||
lowIsland,
|
||||
continents,
|
||||
archipelago,
|
||||
atoll,
|
||||
mediterranean,
|
||||
peninsula,
|
||||
peninsula,
|
||||
pangea,
|
||||
isthmus,
|
||||
shattered,
|
||||
taklamakan,
|
||||
oldWorld,
|
||||
fractious
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -34,19 +34,19 @@ function editHeightmap() {
|
|||
modules.editHeightmap = true;
|
||||
|
||||
// add listeners
|
||||
document.getElementById("paintBrushes").addEventListener("click", openBrushesPanel);
|
||||
document.getElementById("applyTemplate").addEventListener("click", openTemplateEditor);
|
||||
document.getElementById("convertImage").addEventListener("click", openImageConverter);
|
||||
document.getElementById("heightmapPreview").addEventListener("click", toggleHeightmapPreview);
|
||||
document.getElementById("heightmap3DView").addEventListener("click", changeViewMode);
|
||||
document.getElementById("finalizeHeightmap").addEventListener("click", finalizeHeightmap);
|
||||
document.getElementById("renderOcean").addEventListener("click", mockHeightmap);
|
||||
document.getElementById("templateUndo").addEventListener("click", () => restoreHistory(edits.n - 1));
|
||||
document.getElementById("templateRedo").addEventListener("click", () => restoreHistory(edits.n + 1));
|
||||
byId("paintBrushes").on("click", openBrushesPanel);
|
||||
byId("applyTemplate").on("click", openTemplateEditor);
|
||||
byId("convertImage").on("click", openImageConverter);
|
||||
byId("heightmapPreview").on("click", toggleHeightmapPreview);
|
||||
byId("heightmap3DView").on("click", changeViewMode);
|
||||
byId("finalizeHeightmap").on("click", finalizeHeightmap);
|
||||
byId("renderOcean").on("click", mockHeightmap);
|
||||
byId("templateUndo").on("click", () => restoreHistory(edits.n - 1));
|
||||
byId("templateRedo").on("click", () => restoreHistory(edits.n + 1));
|
||||
|
||||
function enterHeightmapEditMode(type) {
|
||||
editHeightmap.layers = Array.from(mapLayers.querySelectorAll("li:not(.buttonoff)")).map(node => node.id); // store layers preset
|
||||
editHeightmap.layers.forEach(l => document.getElementById(l).click()); // turn off all layers
|
||||
editHeightmap.layers.forEach(l => byId(l).click()); // turn off all layers
|
||||
|
||||
customization = 1;
|
||||
closeDialogs();
|
||||
|
|
@ -113,7 +113,7 @@ function editHeightmap() {
|
|||
if (tooltip.dataset.main) showMainTip();
|
||||
|
||||
// move radius circle if drag mode is active
|
||||
const pressed = document.getElementById("brushesButtons").querySelector("button.pressed");
|
||||
const pressed = byId("brushesButtons").querySelector("button.pressed");
|
||||
if (!pressed) return;
|
||||
moveCircle(p[0], p[1], brushRadius.valueAsNumber, "#333");
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ function editHeightmap() {
|
|||
function finalizeHeightmap() {
|
||||
if (viewbox.select("#heights").selectAll("*").size() < 200)
|
||||
return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
|
||||
if (document.getElementById("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
||||
if (byId("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
||||
|
||||
delete window.edits; // remove global variable
|
||||
redo.disabled = templateRedo.disabled = true;
|
||||
|
|
@ -145,7 +145,7 @@ function editHeightmap() {
|
|||
|
||||
customization = 0;
|
||||
customizationMenu.style.display = "none";
|
||||
if (document.getElementById("options").querySelector(".tab > button.active").id === "toolsTab") toolsContent.style.display = "block";
|
||||
if (byId("options").querySelector(".tab > button.active").id === "toolsTab") toolsContent.style.display = "block";
|
||||
layersPreset.disabled = false;
|
||||
exitCustomization.style.display = "none"; // hide finalize button
|
||||
restoreDefaultEvents();
|
||||
|
|
@ -153,8 +153,8 @@ function editHeightmap() {
|
|||
closeDialogs();
|
||||
resetZoom();
|
||||
|
||||
if (document.getElementById("preview")) document.getElementById("preview").remove();
|
||||
if (document.getElementById("canvas3d")) enterStandardView();
|
||||
if (byId("preview")) byId("preview").remove();
|
||||
if (byId("canvas3d")) enterStandardView();
|
||||
|
||||
const mode = heightmapEditMode.innerHTML;
|
||||
if (mode === "erase") regenerateErasedData();
|
||||
|
|
@ -163,7 +163,7 @@ function editHeightmap() {
|
|||
|
||||
// restore initial layers
|
||||
//viewbox.select("#heights").remove();
|
||||
document.getElementById("heights").remove();
|
||||
byId("heights").remove();
|
||||
turnButtonOff("toggleHeight");
|
||||
document
|
||||
.getElementById("mapLayers")
|
||||
|
|
@ -487,8 +487,8 @@ function editHeightmap() {
|
|||
|
||||
function updateStatistics() {
|
||||
const landCells = grid.cells.h.reduce((s, h) => (h >= 20 ? s + 1 : s));
|
||||
landmassCounter.innerHTML = /* html */ `${landCells} (${rn((landCells / grid.cells.i.length) * 100)}%)`;
|
||||
landmassAverage.innerHTML = rn(d3.mean(grid.cells.h));
|
||||
byId("landmassCounter").innerText = `${landCells} (${rn((landCells / grid.cells.i.length) * 100)}%)`;
|
||||
byId("landmassAverage").innerText = rn(d3.mean(grid.cells.h));
|
||||
}
|
||||
|
||||
function updateHistory(noStat) {
|
||||
|
|
@ -501,8 +501,8 @@ function editHeightmap() {
|
|||
redo.disabled = templateRedo.disabled = true;
|
||||
if (!noStat) {
|
||||
updateStatistics();
|
||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
if (byId("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (byId("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -516,8 +516,8 @@ function editHeightmap() {
|
|||
mockHeightmap();
|
||||
updateStatistics();
|
||||
|
||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
if (byId("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (byId("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
}
|
||||
|
||||
// restart edits from 1st step
|
||||
|
|
@ -543,31 +543,31 @@ function editHeightmap() {
|
|||
modules.openBrushesPanel = true;
|
||||
|
||||
// add listeners
|
||||
document.getElementById("brushesButtons").addEventListener("click", e => toggleBrushMode(e));
|
||||
document.getElementById("changeOnlyLand").addEventListener("click", e => changeOnlyLandClick(e));
|
||||
document.getElementById("undo").addEventListener("click", () => restoreHistory(edits.n - 1));
|
||||
document.getElementById("redo").addEventListener("click", () => restoreHistory(edits.n + 1));
|
||||
document.getElementById("rescaleShow").addEventListener("click", () => {
|
||||
document.getElementById("modifyButtons").style.display = "none";
|
||||
document.getElementById("rescaleSection").style.display = "block";
|
||||
byId("brushesButtons").on("click", e => toggleBrushMode(e));
|
||||
byId("changeOnlyLand").on("click", e => changeOnlyLandClick(e));
|
||||
byId("undo").on("click", () => restoreHistory(edits.n - 1));
|
||||
byId("redo").on("click", () => restoreHistory(edits.n + 1));
|
||||
byId("rescaleShow").on("click", () => {
|
||||
byId("modifyButtons").style.display = "none";
|
||||
byId("rescaleSection").style.display = "block";
|
||||
});
|
||||
document.getElementById("rescaleHide").addEventListener("click", () => {
|
||||
document.getElementById("modifyButtons").style.display = "block";
|
||||
document.getElementById("rescaleSection").style.display = "none";
|
||||
byId("rescaleHide").on("click", () => {
|
||||
byId("modifyButtons").style.display = "block";
|
||||
byId("rescaleSection").style.display = "none";
|
||||
});
|
||||
document.getElementById("rescaler").addEventListener("change", e => rescale(e.target.valueAsNumber));
|
||||
document.getElementById("rescaleCondShow").addEventListener("click", () => {
|
||||
document.getElementById("modifyButtons").style.display = "none";
|
||||
document.getElementById("rescaleCondSection").style.display = "block";
|
||||
byId("rescaler").on("change", e => rescale(e.target.valueAsNumber));
|
||||
byId("rescaleCondShow").on("click", () => {
|
||||
byId("modifyButtons").style.display = "none";
|
||||
byId("rescaleCondSection").style.display = "block";
|
||||
});
|
||||
document.getElementById("rescaleCondHide").addEventListener("click", () => {
|
||||
document.getElementById("modifyButtons").style.display = "block";
|
||||
document.getElementById("rescaleCondSection").style.display = "none";
|
||||
byId("rescaleCondHide").on("click", () => {
|
||||
byId("modifyButtons").style.display = "block";
|
||||
byId("rescaleCondSection").style.display = "none";
|
||||
});
|
||||
document.getElementById("rescaleExecute").addEventListener("click", rescaleWithCondition);
|
||||
document.getElementById("smoothHeights").addEventListener("click", smoothAllHeights);
|
||||
document.getElementById("disruptHeights").addEventListener("click", disruptAllHeights);
|
||||
document.getElementById("brushClear").addEventListener("click", startFromScratch);
|
||||
byId("rescaleExecute").on("click", rescaleWithCondition);
|
||||
byId("smoothHeights").on("click", smoothAllHeights);
|
||||
byId("disruptHeights").on("click", disruptAllHeights);
|
||||
byId("brushClear").on("click", startFromScratch);
|
||||
|
||||
function exitBrushMode() {
|
||||
const pressed = document.querySelector("#brushesButtons > button.pressed");
|
||||
|
|
@ -576,7 +576,7 @@ function editHeightmap() {
|
|||
|
||||
viewbox.style("cursor", "default").on(".drag", null);
|
||||
removeCircle();
|
||||
document.getElementById("brushesSliders").style.display = "none";
|
||||
byId("brushesSliders").style.display = "none";
|
||||
}
|
||||
|
||||
const dragBrushThrottled = throttle(dragBrush, 100);
|
||||
|
|
@ -586,7 +586,7 @@ function editHeightmap() {
|
|||
return;
|
||||
}
|
||||
exitBrushMode();
|
||||
document.getElementById("brushesSliders").style.display = "block";
|
||||
byId("brushesSliders").style.display = "block";
|
||||
e.target.classList.add("pressed");
|
||||
viewbox.style("cursor", "crosshair").call(d3.drag().on("start", dragBrushThrottled));
|
||||
}
|
||||
|
|
@ -613,9 +613,7 @@ function editHeightmap() {
|
|||
const power = brushPower.valueAsNumber;
|
||||
const interpolate = d3.interpolateRound(power, 1);
|
||||
const land = changeOnlyLand.checked;
|
||||
function lim(v) {
|
||||
return minmax(v, land ? 20 : 0, 100);
|
||||
}
|
||||
const lim = v => minmax(v, land ? 20 : 0, 100);
|
||||
const h = grid.cells.h;
|
||||
|
||||
const brush = document.querySelector("#brushesButtons > button.pressed").id;
|
||||
|
|
@ -644,21 +642,15 @@ function editHeightmap() {
|
|||
const land = changeOnlyLand.checked;
|
||||
grid.cells.h = grid.cells.h.map(h => (land && (h < 20 || h + v < 20) ? h : lim(h + v)));
|
||||
updateHeightmap();
|
||||
document.getElementById("rescaler").value = 0;
|
||||
byId("rescaler").value = 0;
|
||||
}
|
||||
|
||||
function rescaleWithCondition() {
|
||||
const range = rescaleLower.value + "-" + rescaleHigher.value;
|
||||
const operator = conditionSign.value;
|
||||
const operand = rescaleModifier.valueAsNumber;
|
||||
if (Number.isNaN(operand)) {
|
||||
tip("Operand should be a number", false, "error");
|
||||
return;
|
||||
}
|
||||
if ((operator === "add" || operator === "subtract") && !Number.isInteger(operand)) {
|
||||
tip("Operand should be an integer", false, "error");
|
||||
return;
|
||||
}
|
||||
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");
|
||||
|
||||
if (operator === "multiply") HeightmapGenerator.modify(range, 0, operand, 0);
|
||||
else if (operator === "divide") HeightmapGenerator.modify(range, 0, 1 / operand, 0);
|
||||
|
|
@ -680,15 +672,10 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function startFromScratch() {
|
||||
if (changeOnlyLand.checked) {
|
||||
tip("Not allowed when 'Change only land cells' mode is set", false, "error");
|
||||
return;
|
||||
}
|
||||
if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
|
||||
const someHeights = grid.cells.h.some(h => h);
|
||||
if (!someHeights) {
|
||||
tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
|
||||
return;
|
||||
}
|
||||
if (!someHeights) return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
|
||||
|
||||
grid.cells.h = new Uint8Array(grid.cells.i.length);
|
||||
viewbox.select("#heights").selectAll("*").remove();
|
||||
updateHistory();
|
||||
|
|
@ -697,7 +684,7 @@ function editHeightmap() {
|
|||
|
||||
function openTemplateEditor() {
|
||||
if ($("#templateEditor").is(":visible")) return;
|
||||
const body = document.getElementById("templateBody");
|
||||
const $body = byId("templateBody");
|
||||
|
||||
$("#templateEditor").dialog({
|
||||
title: "Template Editor",
|
||||
|
|
@ -713,13 +700,13 @@ function editHeightmap() {
|
|||
$("#templateBody").sortable({items: "> div", handle: ".icon-resize-vertical", containment: "#templateBody", axis: "y"});
|
||||
|
||||
// add listeners
|
||||
body.addEventListener("click", function (ev) {
|
||||
$body.on("click", function (ev) {
|
||||
const el = ev.target;
|
||||
if (el.classList.contains("icon-check")) {
|
||||
el.classList.remove("icon-check");
|
||||
el.classList.add("icon-check-empty");
|
||||
el.parentElement.style.opacity = 0.5;
|
||||
body.dataset.changed = 1;
|
||||
$body.dataset.changed = 1;
|
||||
return;
|
||||
}
|
||||
if (el.classList.contains("icon-check-empty")) {
|
||||
|
|
@ -734,71 +721,146 @@ function editHeightmap() {
|
|||
}
|
||||
});
|
||||
|
||||
document.getElementById("templateTools").addEventListener("click", e => addStepOnClick(e));
|
||||
document.getElementById("templateSelect").addEventListener("change", e => selectTemplate(e));
|
||||
document.getElementById("templateRun").addEventListener("click", executeTemplate);
|
||||
document.getElementById("templateSave").addEventListener("click", downloadTemplate);
|
||||
document.getElementById("templateLoad").addEventListener("click", () => templateToLoad.click());
|
||||
document.getElementById("templateToLoad").addEventListener("change", function () {
|
||||
byId("templateEditor").on("keypress", event => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
executeTemplate();
|
||||
}
|
||||
});
|
||||
|
||||
byId("templateTools").on("click", addStepOnClick);
|
||||
byId("templateSelect").on("change", selectTemplate);
|
||||
byId("templateRun").on("click", executeTemplate);
|
||||
byId("templateSave").on("click", downloadTemplate);
|
||||
byId("templateLoad").on("click", () => templateToLoad.click());
|
||||
byId("templateToLoad").on("change", function () {
|
||||
uploadFile(this, uploadTemplate);
|
||||
});
|
||||
|
||||
function addStepOnClick(e) {
|
||||
if (e.target.tagName !== "BUTTON") return;
|
||||
const type = e.target.id.replace("template", "");
|
||||
document.getElementById("templateBody").dataset.changed = 1;
|
||||
const type = e.target.dataset.type;
|
||||
byId("templateBody").dataset.changed = 1;
|
||||
addStep(type);
|
||||
}
|
||||
|
||||
function addStep(type, count, dist, arg4, arg5) {
|
||||
const body = document.getElementById("templateBody");
|
||||
body.insertAdjacentHTML("beforeend", getStepHTML(type, count, dist, arg4, arg5));
|
||||
const elDist = body.querySelector("div:last-child").querySelector(".templateDist");
|
||||
if (elDist) elDist.addEventListener("change", setRange);
|
||||
if (dist && elDist && elDist.tagName === "SELECT") {
|
||||
for (const o of elDist.options) {
|
||||
if (o.value === dist) elDist.value = dist;
|
||||
const $body = byId("templateBody");
|
||||
$body.insertAdjacentHTML("beforeend", getStepHTML(type, count, dist, arg4, arg5));
|
||||
|
||||
const $elDist = $body.querySelector("div:last-child > span > .templateDist");
|
||||
if ($elDist) $elDist.on("change", setRange);
|
||||
|
||||
if (dist && $elDist && $elDist.tagName === "SELECT") {
|
||||
for (const option of $elDist.options) {
|
||||
if (option.value === dist) $elDist.value = dist;
|
||||
}
|
||||
if (elDist.value !== dist) {
|
||||
if ($elDist.value !== dist) {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = opt.innerHTML = dist;
|
||||
elDist.add(opt);
|
||||
elDist.value = dist;
|
||||
$elDist.add(opt);
|
||||
$elDist.value = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStepHTML(type, count, arg3, arg4, arg5) {
|
||||
const Trash = `<i class="icon-trash-empty pointer" data-tip="Click to remove the step"></i>`;
|
||||
const Hide = `<div class="icon-check" data-tip="Click to skip the step"></div>`;
|
||||
const Reorder = `<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>`;
|
||||
const common = `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`;
|
||||
const Trash = /* html */ `<i class="icon-trash-empty pointer" data-tip="Click to remove the step"></i>`;
|
||||
const Hide = /* html */ `<div class="icon-check" data-tip="Click to skip the step"></div>`;
|
||||
const Reorder = /* html */ `<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>`;
|
||||
const common = /* html */ `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`;
|
||||
|
||||
const TempY = `<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"}></span>`;
|
||||
const TempX = `<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"}></span>`;
|
||||
const Height = `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${
|
||||
arg3 || "40-50"
|
||||
}></span>`;
|
||||
const Count = `<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"}></span>`;
|
||||
const blob = `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
||||
const TempY = /* html */ `<span>y:
|
||||
<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"} />
|
||||
</span>`;
|
||||
|
||||
const TempX = /* html */ `<span>x:
|
||||
<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"} />
|
||||
</span>`;
|
||||
|
||||
const Height = /* html */ `<span>h:
|
||||
<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${arg3 || "40-50"} />
|
||||
</span>`;
|
||||
|
||||
const Count = /* html */ `<span>n:
|
||||
<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"} />
|
||||
</span>`;
|
||||
|
||||
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return /* html */ `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
||||
|
||||
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return blob;
|
||||
if (type === "Strait")
|
||||
return `${common}<span>d:<select class="templateDist" data-tip="Strait direction"><option value="vertical" selected>vertical</option><option value="horizontal">horizontal</option></select></span><span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${
|
||||
count || "2-7"
|
||||
}></span></div>`;
|
||||
return /* html */ `${common}
|
||||
<span>d:
|
||||
<select class="templateDist" data-tip="Strait direction">
|
||||
<option value="vertical" selected>vertical</option>
|
||||
<option value="horizontal">horizontal</option>
|
||||
</select>
|
||||
</span>
|
||||
<span>w:
|
||||
<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"} />
|
||||
</span>
|
||||
</div>`;
|
||||
|
||||
if (type === "Invert")
|
||||
return /* html */ `${common}
|
||||
<span>by:
|
||||
<select class="templateDist" data-tip="Mirror heightmap along axis" style="width: 7.8em">
|
||||
<option value="x" selected>x</option>
|
||||
<option value="y">y</option>
|
||||
<option value="xy">both</option>
|
||||
</select>
|
||||
</span>
|
||||
<span>n:
|
||||
<input class="templateCount" data-tip="Probability of inversion, range 0-1" value=${count || "0.5"} />
|
||||
</span>
|
||||
</div>`;
|
||||
|
||||
if (type === "Mask")
|
||||
return /* html */ `${common}
|
||||
<span>f:
|
||||
<input class="templateCount"
|
||||
data-tip="Set masking fraction. 1 - full insulation (prevent land on map edges), 2 - half-insulation, etc. Negative number to inverse the effect"
|
||||
type="number" min=-10 max=10 value=${count || 1} />
|
||||
</span>
|
||||
</div>`;
|
||||
|
||||
if (type === "Add")
|
||||
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" type="number" value=${
|
||||
count || -10
|
||||
} min=-100 max=100 step=1></span></div>`;
|
||||
return /* html */ `${common}
|
||||
<span>to:
|
||||
<select class="templateDist" data-tip="Change only land or all cells">
|
||||
<option value="all" selected>all cells</option>
|
||||
<option value="land">land only</option>
|
||||
<option value="interval">interval</option>
|
||||
</select>
|
||||
</span>
|
||||
<span>v:
|
||||
<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)"
|
||||
type="number" value=${count || -10} min=-100 max=100 step=1 />
|
||||
</span>
|
||||
</div>`;
|
||||
|
||||
if (type === "Multiply")
|
||||
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" value=${
|
||||
count || 1.1
|
||||
} min=0 max=10 step=.1></span></div>`;
|
||||
return /* html */ `${common}
|
||||
<span>to:
|
||||
<select class="templateDist" data-tip="Change only land or all cells">
|
||||
<option value="all" selected>all cells</option>
|
||||
<option value="land">land only</option>
|
||||
<option value="interval">interval</option>
|
||||
</select>
|
||||
</span>
|
||||
<span>v:
|
||||
<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number"
|
||||
value=${count || 1.1} min=0 max=10 step=.1 />
|
||||
</span>
|
||||
</div>`;
|
||||
|
||||
if (type === "Smooth")
|
||||
return `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." type="number" min=1 max=10 value=${
|
||||
count || 2
|
||||
}></span></div>`;
|
||||
return /* html */ `${common}
|
||||
<span>f:
|
||||
<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc."
|
||||
type="number" min=1 max=10 step=1 value=${count || 2} />
|
||||
</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function setRange(event) {
|
||||
|
|
@ -813,7 +875,7 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function selectTemplate(e) {
|
||||
const body = document.getElementById("templateBody");
|
||||
const body = byId("templateBody");
|
||||
const steps = body.querySelectorAll("div").length;
|
||||
const changed = +body.getAttribute("data-changed");
|
||||
const template = e.target.value;
|
||||
|
|
@ -839,7 +901,7 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function changeTemplate(template) {
|
||||
const body = document.getElementById("templateBody");
|
||||
const body = byId("templateBody");
|
||||
body.setAttribute("data-changed", 0);
|
||||
body.innerHTML = "";
|
||||
|
||||
|
|
@ -856,43 +918,47 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function executeTemplate() {
|
||||
const body = document.getElementById("templateBody");
|
||||
const steps = body.querySelectorAll("#templateBody > div");
|
||||
const steps = byId("templateBody").querySelectorAll("#templateBody > div");
|
||||
if (!steps.length) return;
|
||||
|
||||
const {addHill, addPit, addRange, addTrough, addStrait, modify, smooth} = HeightmapGenerator;
|
||||
grid.cells.h = new Uint8Array(grid.cells.i.length); // clean all heights
|
||||
|
||||
const seed = byId("templateSeed").value;
|
||||
if (seed) Math.random = aleaPRNG(seed);
|
||||
restartHistory();
|
||||
|
||||
for (const step of steps) {
|
||||
if (step.style.opacity === "0.5") continue;
|
||||
const type = step.dataset.type;
|
||||
|
||||
const count = step.querySelector(".templateCount")?.value || "";
|
||||
const height = step.querySelector(".templateHeight")?.value || "";
|
||||
const dist = step.querySelector(".templateDist")?.value || null;
|
||||
const x = step.querySelector(".templateX")?.value || null;
|
||||
const y = step.querySelector(".templateY")?.value || null;
|
||||
const type = step.dataset.type;
|
||||
|
||||
if (type === "Hill") addHill(count, height, x, y);
|
||||
else if (type === "Pit") addPit(count, height, x, y);
|
||||
else if (type === "Range") addRange(count, height, x, y);
|
||||
else if (type === "Trough") addTrough(count, height, x, y);
|
||||
else if (type === "Strait") addStrait(count, dist);
|
||||
else if (type === "Add") modify(dist, +count, 1);
|
||||
else if (type === "Multiply") modify(dist, 0, +count);
|
||||
else if (type === "Smooth") smooth(+count);
|
||||
if (type === "Hill") HeightmapGenerator.addHill(count, height, x, y);
|
||||
else if (type === "Pit") HeightmapGenerator.addPit(count, height, x, y);
|
||||
else if (type === "Range") HeightmapGenerator.addRange(count, height, x, y);
|
||||
else if (type === "Trough") HeightmapGenerator.addTrough(count, height, x, y);
|
||||
else if (type === "Strait") HeightmapGenerator.addStrait(count, dist);
|
||||
else if (type === "Mask") HeightmapGenerator.mask(+count);
|
||||
else if (type === "Invert") HeightmapGenerator.invert(+count, dist);
|
||||
else if (type === "Add") HeightmapGenerator.modify(dist, +count, 1);
|
||||
else if (type === "Multiply") HeightmapGenerator.modify(dist, 0, +count);
|
||||
else if (type === "Smooth") HeightmapGenerator.smooth(+count);
|
||||
|
||||
updateHistory("noStat"); // update history every step
|
||||
updateHistory("noStat"); // update history on every step
|
||||
}
|
||||
|
||||
updateStatistics();
|
||||
mockHeightmap();
|
||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
if (byId("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if (byId("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
|
||||
}
|
||||
|
||||
function downloadTemplate() {
|
||||
const body = document.getElementById("templateBody");
|
||||
const body = byId("templateBody");
|
||||
body.dataset.changed = 0;
|
||||
const steps = body.querySelectorAll("#templateBody > div");
|
||||
if (!steps.length) return;
|
||||
|
|
@ -977,18 +1043,18 @@ function editHeightmap() {
|
|||
})();
|
||||
|
||||
// add listeners
|
||||
document.getElementById("convertImageLoad").addEventListener("click", () => imageToLoad.click());
|
||||
document.getElementById("imageToLoad").addEventListener("change", loadImage);
|
||||
document.getElementById("convertAutoLum").addEventListener("click", () => autoAssing("lum"));
|
||||
document.getElementById("convertAutoHue").addEventListener("click", () => autoAssing("hue"));
|
||||
document.getElementById("convertAutoFMG").addEventListener("click", () => autoAssing("scheme"));
|
||||
document.getElementById("convertColorsButton").addEventListener("click", setConvertColorsNumber);
|
||||
document.getElementById("convertComplete").addEventListener("click", applyConversion);
|
||||
document.getElementById("convertCancel").addEventListener("click", cancelConversion);
|
||||
document.getElementById("convertOverlay").addEventListener("input", function () {
|
||||
byId("convertImageLoad").on("click", () => imageToLoad.click());
|
||||
byId("imageToLoad").on("change", loadImage);
|
||||
byId("convertAutoLum").on("click", () => autoAssing("lum"));
|
||||
byId("convertAutoHue").on("click", () => autoAssing("hue"));
|
||||
byId("convertAutoFMG").on("click", () => autoAssing("scheme"));
|
||||
byId("convertColorsButton").on("click", setConvertColorsNumber);
|
||||
byId("convertComplete").on("click", applyConversion);
|
||||
byId("convertCancel").on("click", cancelConversion);
|
||||
byId("convertOverlay").on("input", function () {
|
||||
setOverlayOpacity(this.value);
|
||||
});
|
||||
document.getElementById("convertOverlayNumber").addEventListener("input", function () {
|
||||
byId("convertOverlayNumber").on("input", function () {
|
||||
setOverlayOpacity(this.value);
|
||||
});
|
||||
|
||||
|
|
@ -1012,7 +1078,7 @@ function editHeightmap() {
|
|||
document.body.appendChild(img);
|
||||
|
||||
img.onload = function () {
|
||||
const ctx = document.getElementById("canvas").getContext("2d");
|
||||
const ctx = byId("canvas").getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, graphWidth, graphHeight);
|
||||
heightsFromImage(+convertColors.value);
|
||||
resetZoom();
|
||||
|
|
@ -1023,7 +1089,7 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function heightsFromImage(count) {
|
||||
const sourceImage = document.getElementById("canvas");
|
||||
const sourceImage = byId("canvas");
|
||||
const sampleCanvas = document.createElement("canvas");
|
||||
sampleCanvas.width = grid.cellsX;
|
||||
sampleCanvas.height = grid.cellsY;
|
||||
|
|
@ -1062,7 +1128,7 @@ function editHeightmap() {
|
|||
.attr("class", "color-div")
|
||||
.on("click", colorClicked);
|
||||
|
||||
document.getElementById("colorsUnassignedNumber").innerHTML = colors.length;
|
||||
byId("colorsUnassignedNumber").innerHTML = colors.length;
|
||||
}
|
||||
|
||||
function mapClicked() {
|
||||
|
|
@ -1119,8 +1185,8 @@ function editHeightmap() {
|
|||
colorsAssigned.appendChild(selectedColor);
|
||||
colorsAssigned.style.display = "block";
|
||||
|
||||
document.getElementById("colorsUnassignedNumber").innerHTML = colorsUnassigned.childElementCount - 2;
|
||||
document.getElementById("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
||||
byId("colorsUnassignedNumber").innerHTML = colorsUnassigned.childElementCount - 2;
|
||||
byId("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1187,7 +1253,7 @@ function editHeightmap() {
|
|||
|
||||
colorsAssigned.style.display = "block";
|
||||
colorsUnassigned.style.display = "none";
|
||||
document.getElementById("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
||||
byId("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
||||
}
|
||||
|
||||
function setConvertColorsNumber() {
|
||||
|
|
@ -1203,7 +1269,7 @@ function editHeightmap() {
|
|||
|
||||
function setOverlayOpacity(v) {
|
||||
convertOverlay.value = convertOverlayNumber.value = v;
|
||||
document.getElementById("canvas").style.opacity = v;
|
||||
byId("canvas").style.opacity = v;
|
||||
}
|
||||
|
||||
function applyConversion() {
|
||||
|
|
@ -1230,10 +1296,10 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function restoreImageConverterState() {
|
||||
const canvas = document.getElementById("canvas");
|
||||
const canvas = byId("canvas");
|
||||
if (canvas) canvas.remove();
|
||||
|
||||
const image = document.getElementById("imageToConvert");
|
||||
const image = byId("imageToConvert");
|
||||
if (image) image.remove();
|
||||
|
||||
d3.select("#imageConverter").selectAll("div.color-div").remove();
|
||||
|
|
@ -1275,8 +1341,8 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function toggleHeightmapPreview() {
|
||||
if (document.getElementById("preview")) {
|
||||
document.getElementById("preview").remove();
|
||||
if (byId("preview")) {
|
||||
byId("preview").remove();
|
||||
return;
|
||||
}
|
||||
const preview = document.createElement("canvas");
|
||||
|
|
@ -1284,13 +1350,13 @@ function editHeightmap() {
|
|||
preview.width = grid.cellsX;
|
||||
preview.height = grid.cellsY;
|
||||
document.body.insertBefore(preview, optionsContainer);
|
||||
preview.addEventListener("mouseover", () => tip("Heightmap preview. Click to download a screen-sized image"));
|
||||
preview.addEventListener("click", downloadPreview);
|
||||
preview.on("mouseover", () => tip("Heightmap preview. Click to download a screen-sized image"));
|
||||
preview.on("click", downloadPreview);
|
||||
drawHeightmapPreview();
|
||||
}
|
||||
|
||||
function drawHeightmapPreview() {
|
||||
const ctx = document.getElementById("preview").getContext("2d");
|
||||
const ctx = byId("preview").getContext("2d");
|
||||
const imageData = ctx.createImageData(grid.cellsX, grid.cellsY);
|
||||
|
||||
grid.cells.h.forEach((height, i) => {
|
||||
|
|
@ -1306,7 +1372,7 @@ function editHeightmap() {
|
|||
}
|
||||
|
||||
function downloadPreview() {
|
||||
const preview = document.getElementById("preview");
|
||||
const preview = byId("preview");
|
||||
const dataURL = preview.toDataURL("image/png");
|
||||
|
||||
const img = new Image();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
// version and caching control
|
||||
|
||||
const version = "1.82.05"; // generator version, update each time
|
||||
const version = "1.83.0"; // generator version, update each time
|
||||
|
||||
{
|
||||
document.title += " v" + version;
|
||||
|
|
@ -28,6 +28,8 @@ const version = "1.82.05"; // generator version, update each time
|
|||
|
||||
<ul>
|
||||
<strong>Latest changes:</strong>
|
||||
<li>New heightmap template: Fractious</li>
|
||||
<li>Template Editor: mask and invert tools</li>
|
||||
<li>Ability to install the App</li>
|
||||
<li>14 new default fonts</li>
|
||||
<li>Caching for faster startup</li>
|
||||
|
|
@ -35,8 +37,6 @@ const version = "1.82.05"; // generator version, update each time
|
|||
<li>Resample tool by Goteguru</li>
|
||||
<li>Pre-defined heightmaps</li>
|
||||
<li>Advanced notes editor</li>
|
||||
<li>Zones editor: filter by type</li>
|
||||
<li>Color picker: new hatchings</li>
|
||||
</ul>
|
||||
|
||||
<p>Join our <a href="${discord}" target="_blank">Discord server</a> and <a href="${reddit}" target="_blank">Reddit community</a> to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue