Add realm borders + culture annotation overlay, combinable with any colour mode
Political realm borders and realm-name labels were Territory-mode-only (showNationBorders() == mode==Territory), so there was no way to see borders and realm names layered over e.g. the Biome view without losing the terrain-type coloring. Added an independent showRealms bool (key Q, a "Realm borders" toggle in Civilization & Ecology) OR-ed with showNationBorders() at just the border-line and realm-label draw sites (3D, 2D, and exportMapImage() which shares the 2D path) -- mode/vcolors/recolor() are never touched, so this overlay draws over any active colour mode without tinting cells. War fronts and diplomacy arcs stay showNationBorders()-only on purpose, so the combined view doesn't drag in Territory-only clutter. Realm-name labels everywhere they're drawn (Territory view, this new toggle, and the always-on atlas export) now also show the realm's dominant culture as a smaller "(the Velmar)"-style line via Nation.cultureId -> planet.cultureList(). exportAtlasImage() forces showRealms on for the duration of its export (same pattern already used for showSettlements) and adds the culture line as its own lower-priority label candidate in the decluttered pass, anchored below each realm's own label so it drops out gracefully on a dense world via the existing collision check. AtlasLabel::text changed from a raw pointer to an owned std::string since the culture strings are built on the fly. Not reset in regenWorld() -- like showDiplomacy, its underlying nation/ segment lists are already cleared on reseed, so nothing stale can render. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMfyZv91tonDnPJqbaTVJE
This commit is contained in:
parent
cf97ae668d
commit
dae6981dc9
1
BUILD.md
1
BUILD.md
@ -59,6 +59,7 @@ the full ~2.8x speedup; the default uses all cores for no extra gain:
|
|||||||
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 + realm-name labels (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)
|
A toggle alliance/rivalry diplomacy arcs on the Territory view (on by default)
|
||||||
|
Q realm borders + realm-name/culture labels over any colour mode (off 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)
|
||||||
|
|||||||
26
CLAUDE.md
26
CLAUDE.md
@ -422,6 +422,30 @@ on the Live World clock). **Steps 1–7 of the roadmap are done (plus a derived
|
|||||||
"Alliances" checkbox in Overlays), `&&`-ed into just the ally/rival arc draw calls (3D + 2D) so
|
"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
|
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.
|
with or without the arcs. `src/render` only, no save-format change.
|
||||||
|
- **Realm borders + culture annotation over any colour mode** *(done)* — `showNationBorders()`
|
||||||
|
(borders/realm-name labels/war fronts/diplomacy arcs) was Territory-mode-only, so there was no way
|
||||||
|
to see political borders and realm names layered over e.g. the **Biome** view without switching
|
||||||
|
colour modes and losing the terrain-type coloring the user actually wanted to look at. Added an
|
||||||
|
independent `showRealms` bool (default off, key **`Q`**, a "Realm borders" toggle in Civilization &
|
||||||
|
Ecology — like Territory/Culture/Trade it needs settlement/territory data built first, hence
|
||||||
|
shadow+method not a plain checkbox) that's `||`-ed with `showNationBorders()` at just the
|
||||||
|
political-border-segment and realm-name-label draw sites (3D, 2D, and `exportMapImage()` which
|
||||||
|
shares the 2D path) — `mode`/`vcolors`/`recolor()` are never touched, so this overlay draws lines
|
||||||
|
and text *over* whatever colour mode is active without tinting a single cell. War fronts and
|
||||||
|
diplomacy arcs deliberately stay `showNationBorders()`-only so the combined view doesn't also drag
|
||||||
|
in Territory-only clutter. Realm-name labels everywhere they're drawn (Territory view, this new
|
||||||
|
toggle, and the always-on atlas) now also show the realm's dominant culture as a smaller
|
||||||
|
`(the Velmar)`-style line stacked directly above the capital marker, via `Nation.cultureId →
|
||||||
|
planet.cultureList()` (skipped gracefully when absent). `exportAtlasImage()` forces `showRealms` on
|
||||||
|
for the duration of its export (same save/restore pattern already used for `showSettlements`) and
|
||||||
|
adds the culture line as its own lower-priority label candidate in the decluttered pass, anchored
|
||||||
|
just below each realm's own label so it drops out gracefully on a dense world via the existing
|
||||||
|
collision check — no special-casing needed. `AtlasLabel::text` changed from `const std::string*` to
|
||||||
|
an owned `std::string` since the culture strings are built on the fly rather than backed by an
|
||||||
|
existing stable container. Deliberately **not** reset in `regenWorld()` — like `showDiplomacy`, its
|
||||||
|
underlying segment/nation lists are already cleared on reseed, so nothing stale can render; only
|
||||||
|
`mode` needs resetting there. `src/render` only, no save-format or `src/sim` change; ctest
|
||||||
|
unaffected.
|
||||||
- **Toolbar: a direct one-click "Biome view" shortcut** *(done)* — during Tectonics/Hydrology (before
|
- **Toolbar: a direct one-click "Biome view" shortcut** *(done)* — during Tectonics/Hydrology (before
|
||||||
any Civilization & Ecology feature is even relevant) the only way to see the world's actual terrain
|
any Civilization & Ecology feature is even relevant) the only way to see the world's actual terrain
|
||||||
type (deserts/forests/tundra/etc., colour mode `Biome`) was to open the 13-entry View Mode dropdown
|
type (deserts/forests/tundra/etc., colour mode `Biome`) was to open the 13-entry View Mode dropdown
|
||||||
@ -958,6 +982,8 @@ all in 3D + 2D) · `N` day/night terminator (Live World) · `T` tide-coloured co
|
|||||||
`P` territory / realms view + political borders + realm-name labels (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
|
`A` toggle the alliance/rivalry diplomacy arcs on the Territory view (on by default; political
|
||||||
borders/war fronts stay regardless) ·
|
borders/war fronts stay regardless) ·
|
||||||
|
`Q` toggle political realm borders + realm-name (+dominant-culture) labels over **any** colour mode,
|
||||||
|
not just Territory (independent of `P`; off by default) ·
|
||||||
`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 ·
|
||||||
|
|||||||
@ -214,6 +214,7 @@ void drawToolbar(Viewer& v) {
|
|||||||
toggleAction(takeRow(cx, cw, cy), v.planet.settlementsPlaced() ? "Settlements (U)" : "Found settlements (U)",
|
toggleAction(takeRow(cx, cw, cy), v.planet.settlementsPlaced() ? "Settlements (U)" : "Found settlements (U)",
|
||||||
v.showSettlements && v.planet.settlementsPlaced(), &Viewer::placeOrToggleSettlements, v);
|
v.showSettlements && v.planet.settlementsPlaced(), &Viewer::placeOrToggleSettlements, v);
|
||||||
toggleAction(takeRow(cx, cw, cy), "Territory (P)", v.mode == ColorMode::Territory, &Viewer::toggleTerritoryView, v);
|
toggleAction(takeRow(cx, cw, cy), "Territory (P)", v.mode == ColorMode::Territory, &Viewer::toggleTerritoryView, v);
|
||||||
|
toggleAction(takeRow(cx, cw, cy), "Realm borders (Q)", v.showRealms, &Viewer::toggleRealmOverlay, v);
|
||||||
toggleAction(takeRow(cx, cw, cy), "Culture (X)", v.mode == ColorMode::Culture, &Viewer::toggleCultureView, v);
|
toggleAction(takeRow(cx, cw, cy), "Culture (X)", v.mode == ColorMode::Culture, &Viewer::toggleCultureView, v);
|
||||||
toggleAction(takeRow(cx, cw, cy), "Trade / wealth (Z)", v.mode == ColorMode::Wealth, &Viewer::toggleTradeView, v);
|
toggleAction(takeRow(cx, cw, cy), "Trade / wealth (Z)", v.mode == ColorMode::Wealth, &Viewer::toggleTradeView, v);
|
||||||
if (!settledNow) GuiEnable();
|
if (!settledNow) GuiEnable();
|
||||||
|
|||||||
@ -935,6 +935,14 @@ void Viewer::toggleTradeView() { // Z: wealth/trade colour view +
|
|||||||
setStatus(mode == ColorMode::Wealth ? "Wealth / trade on" : "Wealth off");
|
setStatus(mode == ColorMode::Wealth ? "Wealth / trade on" : "Wealth off");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewer::toggleRealmOverlay() { // Q: realm borders + names (+culture) over any colour mode
|
||||||
|
if (!settled) return;
|
||||||
|
if (!planet.settlementsPlaced()) { setStatus("Press U for the dawn of civilization first"); return; }
|
||||||
|
if (!planet.nationsBuilt() || (int)planet.cellNation().size() != (int)planet.cells.size()) rebuildTerritory();
|
||||||
|
showRealms = !showRealms;
|
||||||
|
setStatus(showRealms ? "Realm borders on" : "Realm borders off");
|
||||||
|
}
|
||||||
|
|
||||||
void Viewer::placeOrToggleSettlements() { // U: seed on first press ("the dawn"), then toggle markers
|
void Viewer::placeOrToggleSettlements() { // U: seed on first press ("the dawn"), then toggle markers
|
||||||
if (!settled) return;
|
if (!settled) return;
|
||||||
if (!planet.settlementsPlaced()) {
|
if (!planet.settlementsPlaced()) {
|
||||||
|
|||||||
@ -125,6 +125,13 @@ struct Viewer {
|
|||||||
bool showNationBorders() const { return mode == ColorMode::Territory; }
|
bool showNationBorders() const { return mode == ColorMode::Territory; }
|
||||||
bool showCultureBorders() const { return mode == ColorMode::Culture; }
|
bool showCultureBorders() const { return mode == ColorMode::Culture; }
|
||||||
bool showTradeRoutes() const { return mode == ColorMode::Wealth; }
|
bool showTradeRoutes() const { return mode == ColorMode::Wealth; }
|
||||||
|
bool showRealms = false; // political borders + realm-name (+dominant-culture) labels over
|
||||||
|
// ANY colour mode, not just Territory (key Q) -- ||-ed with
|
||||||
|
// showNationBorders() at just the border-line and realm-label draw
|
||||||
|
// sites, so e.g. the Biome view can show realm borders/names
|
||||||
|
// without nation-tinting cells. War fronts and diplomacy arcs stay
|
||||||
|
// showNationBorders()-only on purpose (Territory-mode-exclusive),
|
||||||
|
// so this overlay never drags in unrelated clutter.
|
||||||
|
|
||||||
// World event journal: currently Live World events, shaped to be reused by later phases.
|
// World event journal: currently Live World events, shaped to be reused by later phases.
|
||||||
struct WorldEvent {
|
struct WorldEvent {
|
||||||
@ -240,6 +247,7 @@ struct Viewer {
|
|||||||
void toggleTerritoryView(); // P
|
void toggleTerritoryView(); // P
|
||||||
void toggleCultureView(); // X
|
void toggleCultureView(); // X
|
||||||
void toggleTradeView(); // Z
|
void toggleTradeView(); // Z
|
||||||
|
void toggleRealmOverlay(); // Q: realm borders + names (+culture) over any colour mode
|
||||||
void placeOrToggleSettlements(); // U
|
void placeOrToggleSettlements(); // U
|
||||||
void toggleHabitabilityView(); // I
|
void toggleHabitabilityView(); // I
|
||||||
void toggleEcoregionView(); // E
|
void toggleEcoregionView(); // E
|
||||||
|
|||||||
@ -204,6 +204,7 @@ void Viewer::handleInput() {
|
|||||||
if (IsKeyPressed(KEY_I)) toggleHabitabilityView();
|
if (IsKeyPressed(KEY_I)) toggleHabitabilityView();
|
||||||
if (IsKeyPressed(KEY_U)) placeOrToggleSettlements();
|
if (IsKeyPressed(KEY_U)) placeOrToggleSettlements();
|
||||||
if (IsKeyPressed(KEY_P)) toggleTerritoryView();
|
if (IsKeyPressed(KEY_P)) toggleTerritoryView();
|
||||||
|
if (IsKeyPressed(KEY_Q)) toggleRealmOverlay();
|
||||||
if (IsKeyPressed(KEY_X)) toggleCultureView();
|
if (IsKeyPressed(KEY_X)) toggleCultureView();
|
||||||
if (IsKeyPressed(KEY_Z)) toggleTradeView();
|
if (IsKeyPressed(KEY_Z)) toggleTradeView();
|
||||||
if (IsKeyPressed(KEY_W)) enterOrLeaveLiveWorld();
|
if (IsKeyPressed(KEY_W)) enterOrLeaveLiveWorld();
|
||||||
|
|||||||
@ -84,7 +84,7 @@ void Viewer::renderGlobe3D() {
|
|||||||
}
|
}
|
||||||
rlEnd(); rlSetLineWidth(1.0f);
|
rlEnd(); rlSetLineWidth(1.0f);
|
||||||
}
|
}
|
||||||
if (showNationBorders() && !nationBorders.empty()) { // political / realm borders (dark, over the tint)
|
if ((showNationBorders() || showRealms) && !nationBorders.empty()) { // political / realm borders (dark, over the tint)
|
||||||
rlSetLineWidth(2.5f); rlBegin(RL_LINES); rlColor4ub(18, 18, 26, 235);
|
rlSetLineWidth(2.5f); rlBegin(RL_LINES); rlColor4ub(18, 18, 26, 235);
|
||||||
for (size_t i = 0; i + 1 < nationBorders.size(); i += 2) {
|
for (size_t i = 0; i + 1 < nationBorders.size(); i += 2) {
|
||||||
rlVertex3f(nationBorders[i].x, nationBorders[i].y, nationBorders[i].z);
|
rlVertex3f(nationBorders[i].x, nationBorders[i].y, nationBorders[i].z);
|
||||||
@ -391,7 +391,7 @@ void Viewer::drawMapOverlays(Rectangle vr, double lonOffset, float scale, float
|
|||||||
if (showGrat) { drawGraticule2D(graticule, vr, lonOffset); drawGraticuleLabels2D(vr, lonOffset); }
|
if (showGrat) { drawGraticule2D(graticule, vr, lonOffset); drawGraticuleLabels2D(vr, lonOffset); }
|
||||||
if (showBorders && !borders.empty()) drawSegments2D(borders, Color{255, 235, 90, 255}, 2.0f * scale, vr, lonOffset);
|
if (showBorders && !borders.empty()) drawSegments2D(borders, Color{255, 235, 90, 255}, 2.0f * scale, vr, lonOffset);
|
||||||
if (showBorders && !ridgeBorders.empty()) drawSegments2D(ridgeBorders, Color{220, 70, 60, 255}, 2.0f * scale, vr, lonOffset);
|
if (showBorders && !ridgeBorders.empty()) drawSegments2D(ridgeBorders, Color{220, 70, 60, 255}, 2.0f * scale, vr, lonOffset);
|
||||||
if (showNationBorders() && !nationBorders.empty()) drawSegments2D(nationBorders, Color{18, 18, 26, 235}, 2.0f * scale, vr, lonOffset);
|
if ((showNationBorders() || showRealms) && !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() && showDiplomacy && !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);
|
||||||
@ -464,10 +464,12 @@ 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
|
// Realm labels (with the territory view, or the independent showRealms overlay over any colour
|
||||||
// 3D realm-label block in renderFrame() -- previously 2D-only had none, so neither the on-screen
|
// mode): name kingdoms/empires at their capital, with the realm's dominant culture as a smaller
|
||||||
// map nor exportMapImage() ever showed realm names, only the 3D globe did.
|
// "(the Velmar)" line stacked just above the marker. Mirrors the 3D realm-label block in
|
||||||
if (drawLabels && showNationBorders() && !planet.nationList().empty()) {
|
// 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() || showRealms) && !planet.nationList().empty()) {
|
||||||
for (const Nation& nat : planet.nationList()) {
|
for (const Nation& nat : planet.nationList()) {
|
||||||
if (nat.tier == NationTier::CityState) continue; // declutter: only multi-settlement realms
|
if (nat.tier == NationTier::CityState) continue; // declutter: only multi-settlement realms
|
||||||
if (nat.capital < 0 || nat.capital >= (int)planet.settlements.size()) continue;
|
if (nat.capital < 0 || nat.capital >= (int)planet.settlements.size()) continue;
|
||||||
@ -478,9 +480,21 @@ void Viewer::drawMapOverlays(Rectangle vr, double lonOffset, float scale, float
|
|||||||
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
||||||
Vector2 lp = projLonLat(lon, lat, lonOffset, vr);
|
Vector2 lp = projLonLat(lon, lat, lonOffset, vr);
|
||||||
if (!CheckCollisionPointRec(lp, vr)) continue;
|
if (!CheckCollisionPointRec(lp, vr)) continue;
|
||||||
|
int cultureFont = std::max(8, font - 4);
|
||||||
|
int nameFillY = (int)lp.y - font - cultureFont - 8 - 2;
|
||||||
int w = MeasureText(nat.name.c_str(), font);
|
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 + 1, nameFillY + 1, 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});
|
DrawText(nat.name.c_str(), (int)lp.x - w / 2, nameFillY, font, Color{245, 235, 210, 255});
|
||||||
|
if (nat.cultureId >= 0 && nat.cultureId < (int)planet.cultureList().size()) {
|
||||||
|
const std::string& cname = planet.cultureList()[nat.cultureId].name;
|
||||||
|
if (!cname.empty()) {
|
||||||
|
std::string ctext = "(" + cname + ")";
|
||||||
|
int cw = MeasureText(ctext.c_str(), cultureFont);
|
||||||
|
int cFillY = (int)lp.y - cultureFont - 8;
|
||||||
|
DrawText(ctext.c_str(), (int)lp.x - cw / 2 + 1, cFillY + 1, cultureFont, Color{0, 0, 0, 205});
|
||||||
|
DrawText(ctext.c_str(), (int)lp.x - cw / 2, cFillY, cultureFont, Color{215, 205, 180, 235});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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
|
||||||
@ -579,11 +593,14 @@ void Viewer::exportAtlasImage() {
|
|||||||
// happens to be.
|
// happens to be.
|
||||||
drawMap2D(planet, vcolors, map2D, er, mapLon);
|
drawMap2D(planet, vcolors, map2D, er, mapLon);
|
||||||
bool savedSettlements = showSettlements;
|
bool savedSettlements = showSettlements;
|
||||||
|
bool savedRealms = showRealms;
|
||||||
showSettlements = true;
|
showSettlements = true;
|
||||||
|
showRealms = true; // the atlas always shows realm borders, regardless of the live toggle
|
||||||
drawMapOverlays(er, mapLon, scale, scale, /*showMinorLabels=*/true, /*drawLabels=*/false);
|
drawMapOverlays(er, mapLon, scale, scale, /*showMinorLabels=*/true, /*drawLabels=*/false);
|
||||||
showSettlements = savedSettlements;
|
showSettlements = savedSettlements;
|
||||||
|
showRealms = savedRealms;
|
||||||
|
|
||||||
struct AtlasLabel { Vector2 pos; const std::string* text; int font; Color col; int priority; float sortKey; bool dot; };
|
struct AtlasLabel { Vector2 pos; std::string text; int font; Color col; int priority; float sortKey; bool dot; };
|
||||||
std::vector<AtlasLabel> labels;
|
std::vector<AtlasLabel> labels;
|
||||||
if (planet.geographyBuilt()) {
|
if (planet.geographyBuilt()) {
|
||||||
for (const GeoFeature& f : planet.geography()) {
|
for (const GeoFeature& f : planet.geography()) {
|
||||||
@ -598,7 +615,7 @@ void Viewer::exportAtlasImage() {
|
|||||||
}
|
}
|
||||||
double lon, lat; dirToLonLat(planet.cells[f.anchorCell].unit, lon, lat);
|
double lon, lat; dirToLonLat(planet.cells[f.anchorCell].unit, lon, lat);
|
||||||
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
||||||
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
|
// Realm names (kingdoms/empires), regardless of the current colour mode -- an atlas is a
|
||||||
@ -616,7 +633,20 @@ void Viewer::exportAtlasImage() {
|
|||||||
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
double lon, lat; dirToLonLat(planet.cells[cell].unit, lon, lat);
|
||||||
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
||||||
lp.y -= font * 0.9f;
|
lp.y -= font * 0.9f;
|
||||||
labels.push_back({ lp, &nat.name, font, Color{245, 235, 210, 255}, prio, (float)nat.totalPop, false });
|
labels.push_back({ lp, nat.name, font, Color{245, 235, 210, 255}, prio, (float)nat.totalPop, false });
|
||||||
|
// The realm's dominant culture, as a smaller "(the Velmar)" label anchored just below the
|
||||||
|
// realm name (still above the raw capital point) -- a lower-priority candidate in the same
|
||||||
|
// greedy pass, so on a dense world it simply drops out on its own if it doesn't fit,
|
||||||
|
// without any special-case logic.
|
||||||
|
if (nat.cultureId >= 0 && nat.cultureId < (int)planet.cultureList().size()) {
|
||||||
|
const std::string& cname = planet.cultureList()[nat.cultureId].name;
|
||||||
|
if (!cname.empty()) {
|
||||||
|
int cfont = std::max(8, (int)std::round(font * 0.72f));
|
||||||
|
Vector2 clp = lp; clp.y += font * 0.62f;
|
||||||
|
labels.push_back({ clp, "(" + cname + ")", cfont, Color{215, 205, 180, 235},
|
||||||
|
prio + 1, (float)nat.totalPop, false });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!planet.settlements.empty()) {
|
if (!planet.settlements.empty()) {
|
||||||
@ -631,7 +661,7 @@ void Viewer::exportAtlasImage() {
|
|||||||
: Color{210, 130, 85, 255};
|
: Color{210, 130, 85, 255};
|
||||||
double lon, lat; dirToLonLat(planet.cells[s.cell].unit, lon, lat);
|
double lon, lat; dirToLonLat(planet.cells[s.cell].unit, lon, lat);
|
||||||
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
Vector2 lp = projLonLat(lon, lat, mapLon, er);
|
||||||
labels.push_back({ lp, &s.name, (int)std::round(font * labelScale), col, prio, (float)s.population, false });
|
labels.push_back({ lp, s.name, (int)std::round(font * labelScale), col, prio, (float)s.population, false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Major features (low priority number) and, within a tier, larger/more populous ones claim
|
// Major features (low priority number) and, within a tier, larger/more populous ones claim
|
||||||
@ -643,8 +673,8 @@ void Viewer::exportAtlasImage() {
|
|||||||
std::vector<Rectangle> placed;
|
std::vector<Rectangle> placed;
|
||||||
const float pad = 3.0f;
|
const float pad = 3.0f;
|
||||||
for (const auto& lb : labels) {
|
for (const auto& lb : labels) {
|
||||||
if (lb.font <= 0 || lb.text->empty() || !CheckCollisionPointRec(lb.pos, er)) continue;
|
if (lb.font <= 0 || lb.text.empty() || !CheckCollisionPointRec(lb.pos, er)) continue;
|
||||||
int w = MeasureText(lb.text->c_str(), lb.font);
|
int w = MeasureText(lb.text.c_str(), lb.font);
|
||||||
Rectangle box{ lb.pos.x - w * 0.5f - pad, lb.pos.y - lb.font * 0.5f - pad,
|
Rectangle box{ lb.pos.x - w * 0.5f - pad, lb.pos.y - lb.font * 0.5f - pad,
|
||||||
(float)w + pad * 2, (float)lb.font + pad * 2 };
|
(float)w + pad * 2, (float)lb.font + pad * 2 };
|
||||||
bool overlap = false;
|
bool overlap = false;
|
||||||
@ -653,8 +683,8 @@ void Viewer::exportAtlasImage() {
|
|||||||
placed.push_back(box);
|
placed.push_back(box);
|
||||||
if (lb.dot) DrawCircleV(lb.pos, 2.5f, lb.col);
|
if (lb.dot) DrawCircleV(lb.pos, 2.5f, lb.col);
|
||||||
int tx = (int)(lb.pos.x - w * 0.5f), ty = (int)(lb.pos.y - lb.font * 0.5f);
|
int tx = (int)(lb.pos.x - w * 0.5f), ty = (int)(lb.pos.y - lb.font * 0.5f);
|
||||||
DrawText(lb.text->c_str(), tx + 1, ty + 1, lb.font, Color{0, 0, 0, 190});
|
DrawText(lb.text.c_str(), tx + 1, ty + 1, lb.font, Color{0, 0, 0, 190});
|
||||||
DrawText(lb.text->c_str(), tx, ty, lb.font, lb.col);
|
DrawText(lb.text.c_str(), tx, ty, lb.font, lb.col);
|
||||||
}
|
}
|
||||||
EndTextureMode();
|
EndTextureMode();
|
||||||
|
|
||||||
@ -1226,8 +1256,10 @@ void Viewer::renderFrame() {
|
|||||||
t == SettleTier::City ? Color{250, 230, 150, 255} : Color{225, 210, 175, 255});
|
t == SettleTier::City ? Color{250, 230, 150, 255} : Color{225, 210, 175, 255});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 3D realm labels (with the territory view): name kingdoms/empires at their capital.
|
// 3D realm labels (with the territory view, or the independent showRealms overlay over any
|
||||||
if (showNationBorders() && !planet.nationList().empty()) {
|
// colour mode): name kingdoms/empires at their capital, with the realm's dominant culture as a
|
||||||
|
// smaller "(the Velmar)" line stacked just above the marker.
|
||||||
|
if ((showNationBorders() || showRealms) && !planet.nationList().empty()) {
|
||||||
Vec3 camPos{cam.position.x, cam.position.y, cam.position.z};
|
Vec3 camPos{cam.position.x, cam.position.y, cam.position.z};
|
||||||
Vec3 forward = (Vec3{cam.target.x, cam.target.y, cam.target.z} - camPos).normalized();
|
Vec3 forward = (Vec3{cam.target.x, cam.target.y, cam.target.z} - camPos).normalized();
|
||||||
Vec3 right = forward.cross(Vec3{cam.up.x, cam.up.y, cam.up.z}).normalized();
|
Vec3 right = forward.cross(Vec3{cam.up.x, cam.up.y, cam.up.z}).normalized();
|
||||||
@ -1246,9 +1278,21 @@ void Viewer::renderFrame() {
|
|||||||
Vec3 rel = lp - camPos; double z = rel.dot(forward); if (z <= 0.0) continue;
|
Vec3 rel = lp - camPos; double z = rel.dot(forward); if (z <= 0.0) continue;
|
||||||
float sx = (float)((rel.dot(right) / (projW * z) * 0.5 + 0.5) * view3DW);
|
float sx = (float)((rel.dot(right) / (projW * z) * 0.5 + 0.5) * view3DW);
|
||||||
float sy = (float)((0.5 - rel.dot(up) / (projH * z) * 0.5) * view3DH);
|
float sy = (float)((0.5 - rel.dot(up) / (projH * z) * 0.5) * view3DH);
|
||||||
|
int cultureFont = std::max(8, font - 4);
|
||||||
|
int nameFillY = (int)sy - font - cultureFont - 8 - 2;
|
||||||
int w = MeasureText(nat.name.c_str(), font);
|
int w = MeasureText(nat.name.c_str(), font);
|
||||||
DrawText(nat.name.c_str(), (int)sx - w / 2 + 1, (int)sy - font - 7, font, Color{0, 0, 0, 205});
|
DrawText(nat.name.c_str(), (int)sx - w / 2 + 1, nameFillY + 1, font, Color{0, 0, 0, 205});
|
||||||
DrawText(nat.name.c_str(), (int)sx - w / 2, (int)sy - font - 8, font, Color{245, 235, 210, 255});
|
DrawText(nat.name.c_str(), (int)sx - w / 2, nameFillY, font, Color{245, 235, 210, 255});
|
||||||
|
if (nat.cultureId >= 0 && nat.cultureId < (int)planet.cultureList().size()) {
|
||||||
|
const std::string& cname = planet.cultureList()[nat.cultureId].name;
|
||||||
|
if (!cname.empty()) {
|
||||||
|
std::string ctext = "(" + cname + ")";
|
||||||
|
int cw = MeasureText(ctext.c_str(), cultureFont);
|
||||||
|
int cFillY = (int)sy - cultureFont - 8;
|
||||||
|
DrawText(ctext.c_str(), (int)sx - cw / 2 + 1, cFillY + 1, cultureFont, Color{0, 0, 0, 205});
|
||||||
|
DrawText(ctext.c_str(), (int)sx - cw / 2, cFillY, cultureFont, Color{215, 205, 180, 235});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user