Refactor layers rendering (#1120)

* feat: render states - use global fn

* feat: render states - separate pole detection from layer render

* feat: render provinces

* chore: unify drawFillWithGap

* refactor: drawIce

* refactor: drawBorders

* refactor: drawHeightmap

* refactor: drawTemperature

* refactor: drawBiomes

* refactor: drawPrec

* refactor: drawPrecipitation

* refactor: drawPopulation

* refactor: drawCells

* refactor: geColor

* refactor: drawMarkers

* refactor: drawScaleBar

* refactor: drawScaleBar

* refactor: drawMilitary

* refactor: pump version to 1.104.00

* refactor: pump version to 1.104.00

* refactor: drawCoastline and createDefaultRuler

* refactor: drawCoastline

* refactor: Features module start

* refactor: features - define distance fields

* feat: drawFeatures

* feat: drawIce don't hide

* feat: detect coastline - fix issue with border feature

* feat: separate labels rendering from generation process

* feat: auto-update and restore layers

* refactor - change layers

* refactor - sort layers

* fix: regenerate burgs to re-render layers

* fix: getColor is not defined

* fix: burgs overview - don't auto-show labels on hover

* fix: redraw population on change

* refactor: improve tooltip logic for burg labels and icons

* chore: pump version to 1.104.0

* fefactor: edit coastline and lake

* fix: minot fixes

* fix: submap

---------

Co-authored-by: Azgaar <azgaar.fmg@yandex.com>
This commit is contained in:
Azgaar 2024-09-20 12:20:27 +02:00 committed by GitHub
parent ec993d1a9b
commit 05de284e02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 2473 additions and 2713 deletions

View file

@ -1,31 +1,26 @@
"use strict";
/*
Cell resampler module used by submapper and resampler (transform)
main function: resample(options);
*/
window.Submap = (function () {
const isWater = (pack, id) => pack.cells.h[id] < 20;
const inMap = (x, y) => x > 0 && x < graphWidth && y > 0 && y < graphHeight;
function resample(parentMap, options) {
/*
/*
generate new map based on an existing one (resampling parentMap)
parentMap: {seed, grid, pack} from original map
options = {
projection: f(Number,Number)->[Number, Number]
function to calculate new coordinates
inverse: g(Number,Number)->[Number, Number]
inverse of f
depressRivers: Bool carve out riverbeds?
smoothHeightMap: Bool run smooth filter on heights
addLakesInDepressions: call FMG original funtion on heightmap
projection: f(Number,Number)->[Number, Number]
function to calculate new coordinates
inverse: g(Number,Number)->[Number, Number]
inverse of f
depressRivers: Bool carve out riverbeds?
smoothHeightMap: Bool run smooth filter on heights
addLakesInDepressions: call FMG original funtion on heightmap
lockMarkers: Bool Auto lock all copied markers
lockBurgs: Bool Auto lock all copied burgs
lockMarkers: Bool Auto lock all copied markers
lockBurgs: Bool Auto lock all copied burgs
}
*/
function resample(parentMap, options) {
const projection = options.projection;
const inverse = options.inverse;
const stage = s => INFO && console.info("SUBMAP:", s);
@ -38,7 +33,6 @@ window.Submap = (function () {
INFO && console.group("SubMap with seed: " + seed);
DEBUG && console.info("Using Options:", options);
// create new grid
applyGraphSize();
grid = generateGrid();
@ -53,7 +47,7 @@ window.Submap = (function () {
}
};
stage("Resampling heightmap, temperature and precipitation.");
stage("Resampling heightmap, temperature and precipitation");
// resample heightmap from old WorldState
const n = grid.points.length;
grid.cells.h = new Uint8Array(n); // heightmap
@ -87,7 +81,7 @@ window.Submap = (function () {
}
if (options.depressRivers) {
stage("Generating riverbeds.");
stage("Generating riverbeds");
const rbeds = new Uint16Array(grid.cells.i.length);
// and erode riverbeds
@ -96,7 +90,7 @@ window.Submap = (function () {
if (oldpc < 0) return; // ignore out-of-map marker (-1)
const oldc = parentMap.pack.cells.g[oldpc];
const targetCells = forwardGridMap[oldc];
if (!targetCells) throw "TargetCell shouldn't be empty.";
if (!targetCells) throw "TargetCell shouldn't be empty";
targetCells.forEach(c => {
if (grid.cells.h[c] < 20) return;
rbeds[c] = 1;
@ -110,33 +104,27 @@ window.Submap = (function () {
});
}
stage("Detect features, ocean and generating lakes.");
markFeatures();
markupGridOcean();
stage("Detect features, ocean and generating lakes");
Features.markupGrid();
// Warning: addLakesInDeepDepressions can be very slow!
if (options.addLakesInDepressions) {
addLakesInDeepDepressions();
openNearSeaLakes();
}
addLakesInDeepDepressions();
openNearSeaLakes();
OceanLayers();
calculateMapCoordinates();
// calculateTemperatures();
// generatePrecipitation();
stage("Cell cleanup.");
calculateTemperatures();
generatePrecipitation();
stage("Cell cleanup");
reGraph();
// remove misclassified cells
stage("Define coastline.");
drawCoastline();
stage("Define coastline");
Features.markupPack();
createDefaultRuler();
/****************************************************/
/* Packed Graph */
/****************************************************/
// Packed Graph
const oldCells = parentMap.pack.cells;
// const reverseMap = new Map(); // cellmap from new -> oldcell
const forwardMap = parentMap.pack.cells.p.map(_ => []); // old -> [newcelllist]
const pn = pack.cells.i.length;
@ -147,7 +135,7 @@ window.Submap = (function () {
cells.religion = new Uint16Array(pn);
cells.province = new Uint16Array(pn);
stage("Resampling culture, state and religion map.");
stage("Resampling culture, state and religion map");
for (const [id, gridCellId] of cells.g.entries()) {
const oldGridId = reverseGridMap[gridCellId];
if (oldGridId === undefined) {
@ -206,14 +194,12 @@ window.Submap = (function () {
forwardMap[oldid].push(id);
}
stage("Regenerating river network.");
stage("Regenerating river network");
Rivers.generate();
drawRivers();
Lakes.defineGroup();
// biome calculation based on (resampled) grid.cells.temp and prec
// it's safe to recalculate.
stage("Regenerating Biome.");
stage("Regenerating Biome");
Biomes.define();
// recalculate suitability and population
// TODO: normalize according to the base-map
@ -234,11 +220,11 @@ window.Submap = (function () {
c.center = newCenters.length ? newCenters[0] : pack.cells.culture.findIndex(x => x === i);
});
stage("Porting and locking burgs.");
stage("Porting and locking burgs");
copyBurgs(parentMap, projection, options);
// transfer states, mark states without land as removed.
stage("Porting states.");
stage("Porting states");
const validStates = new Set(pack.cells.state);
pack.states = parentMap.pack.states;
// keep valid states and neighbors only
@ -252,9 +238,10 @@ window.Submap = (function () {
? pack.burgs[s.capital].cell // capital is the best bet
: pack.cells.state.findIndex(x => x === i); // otherwise use the first valid cell
});
BurgsAndStates.getPoles();
// transfer provinces, mark provinces without land as removed.
stage("Porting provinces.");
stage("Porting provinces");
const validProvinces = new Set(pack.cells.province);
pack.provinces = parentMap.pack.provinces;
// mark uneccesary provinces
@ -267,20 +254,15 @@ window.Submap = (function () {
const newCenters = forwardMap[p.center];
p.center = newCenters.length ? newCenters[0] : pack.cells.province.findIndex(x => x === i);
});
Provinces.getPoles();
BurgsAndStates.drawBurgs();
stage("Regenerating routes network.");
stage("Regenerating routes network");
regenerateRoutes();
drawStates();
drawBorders();
drawStateLabels();
Rivers.specify();
Lakes.generateName();
Features.specify();
stage("Porting military.");
stage("Porting military");
for (const s of pack.states) {
if (!s.military) continue;
for (const m of s.military) {
@ -291,9 +273,8 @@ window.Submap = (function () {
}
s.military = s.military.filter(m => m.cell).map((m, i) => ({...m, i}));
}
Military.redraw();
stage("Copying markers.");
stage("Copying markers");
for (const m of pack.markers) {
const [x, y] = projection(m.x, m.y);
if (!inMap(x, y)) {
@ -307,14 +288,12 @@ window.Submap = (function () {
}
if (layerIsOn("toggleMarkers")) drawMarkers();
stage("Redraw emblems.");
drawEmblems();
stage("Regenerating Zones.");
stage("Regenerating Zones");
Zones.generate();
Names.getMapName();
stage("Restoring Notes.");
stage("Restoring Notes");
notes = parentMap.notes;
stage("Submap done.");
stage("Submap done");
WARN && console.warn(`TOTAL: ${rn((performance.now() - timeStart) / 1000, 2)}s`);
showStatistics();