Add realm names to the 2D map/exports; make diplomacy arcs a separate toggle
Kingdom/empire capital labels only ever drew on the 3D globe -- neither the on-screen 2D map nor exportMapImage()/exportAtlasImage() showed them. drawMapOverlays() now has a 2D realm-label block mirroring the existing 3D one; exportAtlasImage() adds nation names as label candidates in its decluttered pass (offset above the capital's own settlement-name anchor so the two don't collide), shown regardless of the current colour mode since the atlas is a reference, not "what you're looking at". Also split the Territory view's political borders from its alliance/rivalry diplomacy arcs, which previously always showed together with no way to hide just the arcs. New independent showDiplomacy toggle (key A, default on, a toolbar checkbox in Overlays) gates only the ally/rival arc draw calls. Verified end to end: exported both Map and Atlas images from a live world with several realms and confirmed realm names render correctly (cleanly decluttered in the Atlas, alongside geography and settlement names). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMfyZv91tonDnPJqbaTVJE
This commit is contained in:
parent
7cc44cda84
commit
a5b0d76c9c
3
BUILD.md
3
BUILD.md
@ -57,7 +57,8 @@ the full ~2.8x speedup; the default uses all cores for no extra gain:
|
|||||||
E ecoregions colour view (names ecological provinces on first use; Eco tab)
|
E ecoregions colour view (names ecological provinces on first use; Eco tab)
|
||||||
I habitability heat map (where civilization can thrive)
|
I habitability heat map (where civilization can thrive)
|
||||||
U settlements: the dawn of civilization on first press, then toggle markers (Civ tab)
|
U settlements: the dawn of civilization on first press, then toggle markers (Civ tab)
|
||||||
P territory / realms view + borders + war fronts + alliance/rivalry arcs (Realms tab)
|
P territory / realms view + borders + war fronts + realm-name labels (Realms tab)
|
||||||
|
A toggle alliance/rivalry diplomacy arcs on the Territory view (on by default)
|
||||||
X culture / faiths view + cultural borders (peoples/ethos/religion in the Cultures tab)
|
X culture / faiths view + cultural borders (peoples/ethos/religion in the Cultures tab)
|
||||||
Z wealth / trade view + trade routes (sea/river/overland; prosperity feeds city growth)
|
Z wealth / trade view + trade routes (sea/river/overland; prosperity feeds city growth)
|
||||||
Y follow-cam: cycle the 3D camera through active storms (Live World; off after last)
|
Y follow-cam: cycle the 3D camera through active storms (Live World; off after last)
|
||||||
|
|||||||
20
CLAUDE.md
20
CLAUDE.md
@ -406,6 +406,22 @@ on the Live World clock). **Steps 1–7 of the roadmap are done (plus a derived
|
|||||||
etc., now zero-arg methods on `Viewer`, e.g. `mode == ColorMode::Territory`) instead of stored,
|
etc., now zero-arg methods on `Viewer`, e.g. `mode == ColorMode::Territory`) instead of stored,
|
||||||
independently-mutable state — the two can no longer drift apart because there's only one source of
|
independently-mutable state — the two can no longer drift apart because there's only one source of
|
||||||
truth. `src/render` only, no save-format or `src/sim` change; ctest unaffected (`src/sim` untouched).
|
truth. `src/render` only, no save-format or `src/sim` change; ctest unaffected (`src/sim` untouched).
|
||||||
|
- **Realm names in the 2D map/exports + a diplomacy-arc toggle independent of Territory** *(done)* —
|
||||||
|
two follow-up requests after the above fix. (1) Kingdom/empire capital labels ("Kingdom of X") were
|
||||||
|
3D-globe-only (`renderFrame()`'s "3D realm labels" block); neither the on-screen 2D map nor
|
||||||
|
`exportMapImage()`/`exportAtlasImage()` ever drew them. `drawMapOverlays()` now has a matching 2D
|
||||||
|
block (same `showNationBorders() && drawLabels` gating, `projLonLat` instead of the 3D camera
|
||||||
|
projection; city-states skipped same as the 3D version) — fixes the on-screen map and
|
||||||
|
`exportMapImage()` in one place. `exportAtlasImage()` separately adds nation names as label
|
||||||
|
candidates in its decluttered pass (priority tier alongside cities; skipped for city-states), offset
|
||||||
|
above the capital's own settlement-name anchor so the two don't fight over one box; shown regardless
|
||||||
|
of the current colour mode, consistent with the atlas being a reference rather than "what you're
|
||||||
|
looking at". (2) `showNationBorders()` (Territory view) used to unconditionally show the political
|
||||||
|
borders **and** the Step-6 alliance/rivalry arcs together — no way to see realm borders without the
|
||||||
|
diplomacy lines. Added an independent `showDiplomacy` bool (default on, key **`A`**, a toolbar
|
||||||
|
"Alliances" checkbox in Overlays), `&&`-ed into just the ally/rival arc draw calls (3D + 2D) so
|
||||||
|
political borders/war fronts still show under Territory regardless — Territory now toggles cleanly
|
||||||
|
with or without the arcs. `src/render` only, no save-format change.
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
@ -930,7 +946,9 @@ all in 3D + 2D) · `N` day/night terminator (Live World) · `T` tide-coloured co
|
|||||||
`V` volcano markers (Live World) · `M` place-name labels (the atlas; names the world on first use) ·
|
`V` volcano markers (Live World) · `M` place-name labels (the atlas; names the world on first use) ·
|
||||||
`E` ecoregions colour view (names ecology on first use) · `I` habitability heat map ·
|
`E` ecoregions colour view (names ecology on first use) · `I` habitability heat map ·
|
||||||
`U` settlements (the dawn of civilization on first press; toggles markers after) ·
|
`U` settlements (the dawn of civilization on first press; toggles markers after) ·
|
||||||
`P` territory / realms view + political borders (Realms tab lists nations) ·
|
`P` territory / realms view + political borders + realm-name labels (Realms tab lists nations) ·
|
||||||
|
`A` toggle the alliance/rivalry diplomacy arcs on the Territory view (on by default; political
|
||||||
|
borders/war fronts stay regardless) ·
|
||||||
`X` culture / faiths view + cultural borders (Cultures tab lists peoples, ethos & religion) ·
|
`X` culture / faiths view + cultural borders (Cultures tab lists peoples, ethos & religion) ·
|
||||||
`Z` wealth / trade view + trade routes (sea/river/overland; prosperity feeds city growth) ·
|
`Z` wealth / trade view + trade routes (sea/river/overland; prosperity feeds city growth) ·
|
||||||
`SPACE` or on-screen button pause ·
|
`SPACE` or on-screen button pause ·
|
||||||
|
|||||||
@ -130,12 +130,13 @@ void drawToolbar(Viewer& v) {
|
|||||||
{"Grid (G)", &v.showGrat}, {"Rivers (J)", &v.showRivers},
|
{"Grid (G)", &v.showGrat}, {"Rivers (J)", &v.showRivers},
|
||||||
{"Day/night (N)", &v.dayNightOn}, {"Tides (T)", &v.showTides},
|
{"Day/night (N)", &v.dayNightOn}, {"Tides (T)", &v.showTides},
|
||||||
{"Currents (O)", &v.showCurrents}, {"Clouds (K)", &v.showClouds},
|
{"Currents (O)", &v.showCurrents}, {"Clouds (K)", &v.showClouds},
|
||||||
{"Volcanoes (V)", &v.showVolcanoes},
|
{"Volcanoes (V)", &v.showVolcanoes}, {"Alliances (A)", &v.showDiplomacy},
|
||||||
};
|
};
|
||||||
|
const int overlayCount = 10;
|
||||||
float halfW = (cw - GAP) * 0.5f;
|
float halfW = (cw - GAP) * 0.5f;
|
||||||
for (int i = 0; i < 9; i += 2) {
|
for (int i = 0; i < overlayCount; i += 2) {
|
||||||
guiCheckRow(Rectangle{ cx, cy, halfW, ROWH }, overlays[i].label, overlays[i].flag);
|
guiCheckRow(Rectangle{ cx, cy, halfW, ROWH }, overlays[i].label, overlays[i].flag);
|
||||||
if (i + 1 < 9) guiCheckRow(Rectangle{ cx + halfW + GAP, cy, halfW, ROWH }, overlays[i + 1].label, overlays[i + 1].flag);
|
if (i + 1 < overlayCount) guiCheckRow(Rectangle{ cx + halfW + GAP, cy, halfW, ROWH }, overlays[i + 1].label, overlays[i + 1].flag);
|
||||||
cy += ROWH + GAP;
|
cy += ROWH + GAP;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
@ -110,6 +110,8 @@ struct Viewer {
|
|||||||
std::vector<Vector3> cultureBorders; // cultural-region border segments (civ Step 4, rebuilt with territory)
|
std::vector<Vector3> cultureBorders; // cultural-region border segments (civ Step 4, rebuilt with territory)
|
||||||
std::vector<Vector3> warFrontier; // red frontier segments between realms currently at war (civ Step 5)
|
std::vector<Vector3> warFrontier; // red frontier segments between realms currently at war (civ Step 5)
|
||||||
std::vector<Vector3> allyLinks, rivalLinks; // civ Step 6: capital-to-capital arcs (allies green, rivals red)
|
std::vector<Vector3> allyLinks, rivalLinks; // civ Step 6: capital-to-capital arcs (allies green, rivals red)
|
||||||
|
bool showDiplomacy = true; // draw the alliance/rivalry arcs above with the Territory view (key A) --
|
||||||
|
// independent of showNationBorders() so Territory can be shown without them
|
||||||
std::vector<Vector3> tradeSea, tradeLand; // civ Step 7: trade routes (sea cyan / river+land amber)
|
std::vector<Vector3> tradeSea, tradeLand; // civ Step 7: trade routes (sea cyan / river+land amber)
|
||||||
long lastTerritoryYear = -1; // sim year territory was last recomputed (recompute when it ticks)
|
long lastTerritoryYear = -1; // sim year territory was last recomputed (recompute when it ticks)
|
||||||
// Whether to draw the political/cultural/trade overlays is *derived* from `mode` -- deliberately
|
// Whether to draw the political/cultural/trade overlays is *derived* from `mode` -- deliberately
|
||||||
|
|||||||
@ -197,6 +197,7 @@ void Viewer::handleInput() {
|
|||||||
if (IsKeyPressed(KEY_D)) showDrift = !showDrift;
|
if (IsKeyPressed(KEY_D)) showDrift = !showDrift;
|
||||||
if (IsKeyPressed(KEY_G)) showGrat = !showGrat;
|
if (IsKeyPressed(KEY_G)) showGrat = !showGrat;
|
||||||
if (IsKeyPressed(KEY_J)) showRivers = !showRivers;
|
if (IsKeyPressed(KEY_J)) showRivers = !showRivers;
|
||||||
|
if (IsKeyPressed(KEY_A)) showDiplomacy = !showDiplomacy; // alliance/rivalry arcs with the Territory view
|
||||||
if (IsKeyPressed(KEY_H)) toggleHydrology();
|
if (IsKeyPressed(KEY_H)) toggleHydrology();
|
||||||
if (IsKeyPressed(KEY_L)) generateOrRegenerateBiota();
|
if (IsKeyPressed(KEY_L)) generateOrRegenerateBiota();
|
||||||
if (IsKeyPressed(KEY_E)) toggleEcoregionView();
|
if (IsKeyPressed(KEY_E)) toggleEcoregionView();
|
||||||
|
|||||||
@ -108,7 +108,7 @@ void Viewer::renderGlobe3D() {
|
|||||||
}
|
}
|
||||||
rlEnd(); rlSetLineWidth(1.0f);
|
rlEnd(); rlSetLineWidth(1.0f);
|
||||||
}
|
}
|
||||||
if (showNationBorders()) { // civ Step 6: diplomacy arcs (allies green, rivals dark red)
|
if (showNationBorders() && showDiplomacy) { // civ Step 6: diplomacy arcs (allies green, rivals dark red)
|
||||||
rlSetLineWidth(2.0f); rlBegin(RL_LINES);
|
rlSetLineWidth(2.0f); rlBegin(RL_LINES);
|
||||||
rlColor4ub(70, 220, 120, 200);
|
rlColor4ub(70, 220, 120, 200);
|
||||||
for (size_t i = 0; i + 1 < allyLinks.size(); i += 2) {
|
for (size_t i = 0; i + 1 < allyLinks.size(); i += 2) {
|
||||||
@ -394,8 +394,8 @@ void Viewer::drawMapOverlays(Rectangle vr, double lonOffset, float scale, float
|
|||||||
if (showNationBorders() && !nationBorders.empty()) drawSegments2D(nationBorders, Color{18, 18, 26, 235}, 2.0f * scale, vr, lonOffset);
|
if (showNationBorders() && !nationBorders.empty()) drawSegments2D(nationBorders, Color{18, 18, 26, 235}, 2.0f * scale, vr, lonOffset);
|
||||||
if (showCultureBorders() && !cultureBorders.empty()) drawSegments2D(cultureBorders, Color{245, 240, 220, 230}, 2.5f * scale, vr, lonOffset);
|
if (showCultureBorders() && !cultureBorders.empty()) drawSegments2D(cultureBorders, Color{245, 240, 220, 230}, 2.5f * scale, vr, lonOffset);
|
||||||
if (showNationBorders() && !warFrontier.empty()) drawSegments2D(warFrontier, Color{235, 40, 30, 255}, 2.5f * scale, vr, lonOffset);
|
if (showNationBorders() && !warFrontier.empty()) drawSegments2D(warFrontier, Color{235, 40, 30, 255}, 2.5f * scale, vr, lonOffset);
|
||||||
if (showNationBorders() && !allyLinks.empty()) drawSegments2D(allyLinks, Color{70, 220, 120, 220}, 1.5f * scale, vr, lonOffset);
|
if (showNationBorders() && showDiplomacy && !allyLinks.empty()) drawSegments2D(allyLinks, Color{70, 220, 120, 220}, 1.5f * scale, vr, lonOffset);
|
||||||
if (showNationBorders() && !rivalLinks.empty()) drawSegments2D(rivalLinks, Color{150, 40, 60, 220}, 1.5f * scale, vr, lonOffset);
|
if (showNationBorders() && showDiplomacy && !rivalLinks.empty()) drawSegments2D(rivalLinks, Color{150, 40, 60, 220}, 1.5f * scale, vr, lonOffset);
|
||||||
if (showTradeRoutes() && !tradeSea.empty()) drawSegments2D(tradeSea, Color{90, 200, 235, 220}, 1.2f * scale, vr, lonOffset);
|
if (showTradeRoutes() && !tradeSea.empty()) drawSegments2D(tradeSea, Color{90, 200, 235, 220}, 1.2f * scale, vr, lonOffset);
|
||||||
if (showTradeRoutes() && !tradeLand.empty()) drawSegments2D(tradeLand, Color{230, 180, 90, 220}, 1.2f * scale, vr, lonOffset);
|
if (showTradeRoutes() && !tradeLand.empty()) drawSegments2D(tradeLand, Color{230, 180, 90, 220}, 1.2f * scale, vr, lonOffset);
|
||||||
if (showDrift && !driftArrows.empty()) drawSegments2D(driftArrows, Color{90, 230, 255, 255}, 2.0f * scale, vr, lonOffset);
|
if (showDrift && !driftArrows.empty()) drawSegments2D(driftArrows, Color{90, 230, 255, 255}, 2.0f * scale, vr, lonOffset);
|
||||||
@ -464,6 +464,25 @@ void Viewer::drawMapOverlays(Rectangle vr, double lonOffset, float scale, float
|
|||||||
DrawText(txt, (int)(lp.x + 4 * scale), (int)(lp.y - 8 * scale), fs, RAYWHITE);
|
DrawText(txt, (int)(lp.x + 4 * scale), (int)(lp.y - 8 * scale), fs, RAYWHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Realm labels (with the territory view): name kingdoms/empires at their capital. Mirrors the
|
||||||
|
// 3D realm-label block in renderFrame() -- previously 2D-only had none, so neither the on-screen
|
||||||
|
// map nor exportMapImage() ever showed realm names, only the 3D globe did.
|
||||||
|
if (drawLabels && showNationBorders() && !planet.nationList().empty()) {
|
||||||
|
for (const Nation& nat : planet.nationList()) {
|
||||||
|
if (nat.tier == NationTier::CityState) continue; // declutter: only multi-settlement realms
|
||||||
|
if (nat.capital < 0 || nat.capital >= (int)planet.settlements.size()) continue;
|
||||||
|
int cell = planet.settlements[nat.capital].cell;
|
||||||
|
if (cell < 0 || cell >= (int)planet.cells.size()) continue;
|
||||||
|
int font = (int)std::round((nat.tier == NationTier::Empire ? 16 : 14) * scale);
|
||||||
|
if (font <= 0) continue;
|
||||||
|
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
||||||
|
Vector2 lp = projLonLat(lon, lat, lonOffset, vr);
|
||||||
|
if (!CheckCollisionPointRec(lp, vr)) continue;
|
||||||
|
int w = MeasureText(nat.name.c_str(), font);
|
||||||
|
DrawText(nat.name.c_str(), (int)lp.x - w / 2 + 1, (int)lp.y - font - 7, font, Color{0, 0, 0, 205});
|
||||||
|
DrawText(nat.name.c_str(), (int)lp.x - w / 2, (int)lp.y - font - 8, font, Color{245, 235, 210, 255});
|
||||||
|
}
|
||||||
|
}
|
||||||
// Place-name labels (the atlas). Minor features only when the map is zoomed in (on-screen) or
|
// Place-name labels (the atlas). Minor features only when the map is zoomed in (on-screen) or
|
||||||
// always for a high-res export, where there's ample room for the full detail. Skipped entirely
|
// always for a high-res export, where there's ample room for the full detail. Skipped entirely
|
||||||
// when the caller (exportAtlasImage) does its own decluttered label pass instead.
|
// when the caller (exportAtlasImage) does its own decluttered label pass instead.
|
||||||
@ -582,6 +601,24 @@ void Viewer::exportAtlasImage() {
|
|||||||
labels.push_back({ lp, &f.name, (int)std::round(font * labelScale), col, prio, (float)f.size, dot });
|
labels.push_back({ lp, &f.name, (int)std::round(font * labelScale), col, prio, (float)f.size, dot });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Realm names (kingdoms/empires), regardless of the current colour mode -- an atlas is a
|
||||||
|
// reference, not "what you're currently looking at". Offset above the capital's own marker/name
|
||||||
|
// (rather than sharing its exact anchor point) so the two don't fight over the same box in the
|
||||||
|
// decluttering pass below; city-states are skipped (bare settlement name already covers them).
|
||||||
|
if (!planet.nationList().empty()) {
|
||||||
|
for (const Nation& nat : planet.nationList()) {
|
||||||
|
if (nat.tier == NationTier::CityState || nat.name.empty()) continue;
|
||||||
|
if (nat.capital < 0 || nat.capital >= (int)planet.settlements.size()) continue;
|
||||||
|
int cell = planet.settlements[nat.capital].cell;
|
||||||
|
if (cell < 0 || cell >= (int)planet.cells.size()) continue;
|
||||||
|
int font = (int)std::round((nat.tier == NationTier::Empire ? 16 : 14) * labelScale);
|
||||||
|
int prio = nat.tier == NationTier::Empire ? 0 : 1;
|
||||||
|
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
||||||
|
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
||||||
|
lp.y -= font * 0.9f;
|
||||||
|
labels.push_back({ lp, &nat.name, font, Color{245, 235, 210, 255}, prio, (float)nat.totalPop, false });
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!planet.settlements.empty()) {
|
if (!planet.settlements.empty()) {
|
||||||
const double townP = planet.cfg.civTownPop, cityP = planet.cfg.civCityPop, abP = planet.cfg.civAbandonPop;
|
const double townP = planet.cfg.civTownPop, cityP = planet.cfg.civCityPop, abP = planet.cfg.civAbandonPop;
|
||||||
for (const Settlement& s : planet.settlements) {
|
for (const Settlement& s : planet.settlements) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user