X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fui%2Fui.cpp;h=c361df55b06858c9d1271cf9c0fc37aa320c4f02;hb=ae4f59520574caf5054d4a19cd76fa86c4a97264;hp=98445b408c5bd2f802960a7ed08ed6f5ab2bb4de;hpb=1f8fe0fd81053821f26787e9809cd1a13f747819;p=blobs.git diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 98445b4..c361df5 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -1,3 +1,4 @@ +#include "BodyPanel.hpp" #include "CreaturePanel.hpp" #include "RecordsPanel.hpp" #include "string.hpp" @@ -7,7 +8,9 @@ #include "Meter.hpp" #include "../app/Assets.hpp" #include "../creature/Creature.hpp" +#include "../creature/Goal.hpp" #include "../graphics/Viewport.hpp" +#include "../math/const.hpp" #include "../world/Body.hpp" #include "../world/Simulation.hpp" @@ -29,6 +32,7 @@ CreaturePanel::CreaturePanel(app::Assets &assets) , born(new Label(assets.fonts.medium)) , age(new Label(assets.fonts.medium)) , mass(new Label(assets.fonts.medium)) +, size(new Label(assets.fonts.medium)) , goal(new Label(assets.fonts.medium)) , pos(new Label(assets.fonts.medium)) , tile(new Label(assets.fonts.medium)) @@ -45,6 +49,8 @@ CreaturePanel::CreaturePanel(app::Assets &assets) age_label->Text("Age"); Label *mass_label = new Label(assets.fonts.medium); mass_label->Text("Mass"); + Label *size_label = new Label(assets.fonts.medium); + size_label->Text("Size"); Label *goal_label = new Label(assets.fonts.medium); goal_label->Text("Goal"); @@ -55,6 +61,7 @@ CreaturePanel::CreaturePanel(app::Assets &assets) ->Add(born_label) ->Add(age_label) ->Add(mass_label) + ->Add(size_label) ->Add(goal_label); Panel *info_value_panel = new Panel; info_value_panel @@ -63,6 +70,7 @@ CreaturePanel::CreaturePanel(app::Assets &assets) ->Add(born) ->Add(age) ->Add(mass) + ->Add(size) ->Add(goal); Panel *info_panel = new Panel; info_panel @@ -189,7 +197,6 @@ CreaturePanel::~CreaturePanel() { void CreaturePanel::Show(creature::Creature &cr) { c = &cr; - name->Text(c->Name()); born->Text(TimeString(c->Born())); if (c->Parents().empty()) { @@ -216,8 +223,10 @@ void CreaturePanel::Hide() noexcept { void CreaturePanel::Draw(graphics::Viewport &viewport) noexcept { if (!c) return; + name->Text(c->Name()); age->Text(TimeString(c->Age())); mass->Text(MassString(c->Mass())); + size->Text(LengthString(c->Size())); if (c->Goals().empty()) { goal->Text("none"); } else { @@ -225,24 +234,21 @@ void CreaturePanel::Draw(graphics::Viewport &viewport) noexcept { } pos->Text(VectorString(c->GetSituation().Position(), 2)); - tile->Text(c->GetSituation().GetTileType().label); + tile->Text(c->GetSituation().GetTileType().label + ( + c->GetSituation().OnGround() + ? (c->GetSituation().Moving() ? " (moving)" : " (standing)") + : (c->GetSituation().Moving() ? " (flying)" : " (hovering)") + )); head->Text(VectorString(c->GetSituation().Heading(), 2)); const creature::Composition &comp = c->GetComposition(); if (comp.size() < components.size()) { + components.clear(); composition->Clear(); - while (comp.size() < components.size()) { - delete components.back(); - components.pop_back(); - } - for (auto l : components) { - composition->Add(l); - } - } else { - while (comp.size() > components.size()) { - components.emplace_back(new Label(assets.fonts.medium)); - composition->Add(components.back()); - } + } + while (comp.size() > components.size()) { + components.emplace_back(new Label(assets.fonts.medium)); + composition->Add(components.back()); } { int i = 0; @@ -265,12 +271,12 @@ void CreaturePanel::Draw(graphics::Viewport &viewport) noexcept { } } - props[0]->Text(DecimalString(c->Strength(), 2)); - props[1]->Text(DecimalString(c->Stamina(), 2)); - props[2]->Text(DecimalString(c->Dexerty(), 2)); - props[3]->Text(DecimalString(c->Intelligence(), 2)); + props[0]->Text(DecimalString(c->Strength(), 2) + " / " + DecimalString(c->GetProperties().Strength(), 2)); + props[1]->Text(DecimalString(c->Stamina(), 2) + " / " + DecimalString(c->GetProperties().Stamina(), 2)); + props[2]->Text(DecimalString(c->Dexerty(), 2) + " / " + DecimalString(c->GetProperties().Dexerty(), 2)); + props[3]->Text(DecimalString(c->Intelligence(), 2) + " / " + DecimalString(c->GetProperties().Intelligence(), 2)); props[4]->Text(TimeString(c->Lifetime())); - props[5]->Text(PercentageString(c->Fertility())); + props[5]->Text(PercentageString(c->Fertility()) + " / " + PercentageString(c->GetProperties().Fertility())); props[6]->Text(PercentageString(c->Mutability())); props[7]->Text(PercentageString(c->Adaptability())); props[8]->Text(MassString(c->OffspringMass())); @@ -282,6 +288,127 @@ void CreaturePanel::Draw(graphics::Viewport &viewport) noexcept { } +BodyPanel::BodyPanel(app::Assets &assets) +: assets(assets) +, body(nullptr) +, name(new Label(assets.fonts.large)) +, mass(new Label(assets.fonts.medium)) +, radius(new Label(assets.fonts.medium)) +, soi(new Label(assets.fonts.medium)) +, operiod(new Label(assets.fonts.medium)) +, rperiod(new Label(assets.fonts.medium)) +, atm(new Label(assets.fonts.medium)) +, sma(new Label(assets.fonts.medium)) +, ecc(new Label(assets.fonts.medium)) +, inc(new Label(assets.fonts.medium)) +, asc(new Label(assets.fonts.medium)) +, arg(new Label(assets.fonts.medium)) +, mna(new Label(assets.fonts.medium)) +, panel() { + Label *mass_label = new Label(assets.fonts.medium); + mass_label->Text("Mass"); + Label *radius_label = new Label(assets.fonts.medium); + radius_label->Text("Radius"); + Label *soi_label = new Label(assets.fonts.medium); + soi_label->Text("SOI"); + Label *operiod_label = new Label(assets.fonts.medium); + operiod_label->Text("Orb. period"); + Label *rperiod_label = new Label(assets.fonts.medium); + rperiod_label->Text("Rot. period"); + Label *atm_label = new Label(assets.fonts.medium); + atm_label->Text("Atmosphere"); + Label *sma_label = new Label(assets.fonts.medium); + sma_label->Text("SMA"); + Label *ecc_label = new Label(assets.fonts.medium); + ecc_label->Text("Eccentricity"); + Label *inc_label = new Label(assets.fonts.medium); + inc_label->Text("Inclination"); + Label *asc_label = new Label(assets.fonts.medium); + asc_label->Text("Asc. node"); + Label *arg_label = new Label(assets.fonts.medium); + arg_label->Text("Arg. Periapsis"); + Label *mna_label = new Label(assets.fonts.medium); + mna_label->Text("Mean anomaly"); + Panel *label_panel = new Panel; + label_panel + ->Direction(Panel::VERTICAL) + ->Add(mass_label) + ->Add(radius_label) + ->Add(soi_label) + ->Add(operiod_label) + ->Add(rperiod_label) + ->Add(atm_label) + ->Add(sma_label) + ->Add(ecc_label) + ->Add(inc_label) + ->Add(asc_label) + ->Add(arg_label) + ->Add(mna_label); + Panel *value_panel = new Panel; + value_panel + ->Direction(Panel::VERTICAL) + ->Add(mass) + ->Add(radius) + ->Add(soi) + ->Add(operiod) + ->Add(rperiod) + ->Add(atm) + ->Add(sma) + ->Add(ecc) + ->Add(inc) + ->Add(asc) + ->Add(arg) + ->Add(mna); + Panel *info_panel = new Panel; + info_panel + ->Direction(Panel::HORIZONTAL) + ->Spacing(10.0f) + ->Add(label_panel) + ->Add(value_panel); + + panel + .Add(name) + ->Add(info_panel) + ->Padding(glm::vec2(10.0f)) + ->Spacing(10.0f) + ->Direction(Panel::VERTICAL) + ->Background(glm::vec4(1.0f, 1.0f, 1.0f, 0.7f)); +} + +BodyPanel::~BodyPanel() { +} + +void BodyPanel::Show(world::Body &b) { + body = &b; + name->Text(b.Name()); + mass->Text(MassString(b.Mass())); + radius->Text(LengthString(b.Radius())); + soi->Text(LengthString(b.SphereOfInfluence())); + operiod->Text(TimeString(b.OrbitalPeriod())); + rperiod->Text(TimeString(b.RotationalPeriod())); + atm->Text(b.HasAtmosphere() ? assets.data.resources[b.Atmosphere()].label : std::string("none")); + sma->Text(LengthString(b.GetOrbit().SemiMajorAxis())); + ecc->Text(DecimalString(b.GetOrbit().Eccentricity(), 3)); + inc->Text(AngleString(b.GetOrbit().Inclination())); + asc->Text(AngleString(b.GetOrbit().LongitudeAscending())); + arg->Text(AngleString(b.GetOrbit().ArgumentPeriapsis())); + mna->Text(AngleString(b.GetOrbit().MeanAnomaly())); +} + +void BodyPanel::Hide() noexcept { + body = nullptr; +} + +void BodyPanel::Draw(graphics::Viewport &viewport) noexcept { + if (!Shown()) return; + + const glm::vec2 margin(20.0f); + panel.Position(glm::vec2(viewport.Width() - margin.x - panel.Size().x, margin.y)); + panel.Layout(); + panel.Draw(assets, viewport); +} + + RecordsPanel::RecordsPanel(world::Simulation &sim) : sim(sim) , records() @@ -313,21 +440,28 @@ RecordsPanel::RecordsPanel(world::Simulation &sim) holders.reserve(sim.Records().size() * (world::Record::MAX + 1)); int ri = 0; for (const auto &r : sim.Records()) { + Panel *by_panel = new Panel; + by_panel + ->Direction(Panel::VERTICAL); + Panel *val_panel = new Panel; + val_panel + ->Direction(Panel::VERTICAL); + Panel *tab_panel = new Panel; + tab_panel + ->Direction(Panel::HORIZONTAL) + ->Spacing(10.0f) + ->Add(by_panel) + ->Add(val_panel); Label *rec_label = new Label(sim.Assets().fonts.medium); rec_label->Text(r.name); - Label *by_label = new Label(sim.Assets().fonts.medium); - by_label->Text("By"); Panel *rec_panel = new Panel; rec_panel ->Direction(Panel::VERTICAL) - ->Add(rec_label); - Panel *by_panel = new Panel; - by_panel - ->Direction(Panel::VERTICAL) - ->Add(by_label); + ->Add(rec_label) + ->Add(tab_panel); for (int i = 0; i < world::Record::MAX; ++i) { Label *val_label = new Label(sim.Assets().fonts.medium); - rec_panel->Add(val_label); + val_panel->Add(val_label); records.push_back(val_label); Label *holder_label = new Label(sim.Assets().fonts.medium); by_panel->Add(holder_label); @@ -337,8 +471,7 @@ RecordsPanel::RecordsPanel(world::Simulation &sim) group_panel ->Direction(Panel::HORIZONTAL) ->Spacing(10.0f) - ->Add(rec_panel) - ->Add(by_panel); + ->Add(rec_panel); panel.Add(group_panel); ++ri; } @@ -425,6 +558,30 @@ void TimePanel::Draw(graphics::Viewport &viewport) noexcept { } +namespace { +std::ostream &custom_fixed(std::ostream &out, double n, int d) { + double f = n; + int p = d; + while (f > 1.0 && p > 0) { + --p; + f *= 0.1; + } + if (p > 0) { + out << std::fixed << std::setprecision(p) << n; + } else { + out.unsetf(std::ios_base::floatfield); + out << std::setprecision(d) << n; + } + return out; +} +} + +std::string AngleString(double a) { + std::stringstream s; + s << std::fixed << std::setprecision(2) << std::fmod(a * 180.0 * PI_inv, 360.0) << "°"; + return s.str(); +} + std::string DecimalString(double n, int p) { std::stringstream s; s << std::fixed << std::setprecision(p) << n; @@ -433,28 +590,38 @@ std::string DecimalString(double n, int p) { std::string LengthString(double m) { std::stringstream s; - s << std::fixed << std::setprecision(3); - if (m > 1500.0) { - s << (m * 0.001) << "km"; - } else if (m < 0.1) { - s << (m * 1000.0) << "mm"; + if (m > 1.5e9) { + custom_fixed(s, m * 1.0e-9, 4) << "Gm"; + } else if (m > 1.5e6) { + custom_fixed(s, m * 1.0e-6, 4) << "Mm"; + } else if (m > 1.5e3) { + custom_fixed(s, m * 1.0e-3, 4) << "km"; + } else if (m < 1.5e-3) { + custom_fixed(s, m * 1.0e3, 4) << "mm"; + } else if (m < 1.5) { + custom_fixed(s, m * 1.0e2, 4) << "cm"; } else { - s << m << "m"; + custom_fixed(s, m, 4) << "m"; } return s.str(); } std::string MassString(double kg) { std::stringstream s; - s << std::fixed << std::setprecision(3); - if (kg > 1500.0) { - s << (kg * 0.001) << "t"; + if (kg > 1.5e12) { + custom_fixed(s, kg * 1.0e-12, 4) << "Gt"; + } else if (kg > 1.5e9) { + custom_fixed(s, kg * 1.0e-9, 4) << "Mt"; + } else if (kg > 1.5e6) { + custom_fixed(s, kg * 1.0e-6, 4) << "kt"; + } else if (kg > 1.5e3) { + custom_fixed(s, kg * 1.0e-3, 4) << "t"; + } else if (kg < 1.0e-3) { + custom_fixed(s, kg * 1.0e6, 4) << "mg"; } else if (kg < 1.0) { - s << (kg * 1000.0) << "g"; - } else if (kg < 0.001) { - s << (kg * 1.0e6) << "mg"; + custom_fixed(s, kg * 1.0e3, 4) << "g"; } else { - s << kg << "kg"; + custom_fixed(s, kg, 4) << "kg"; } return s.str(); } @@ -471,16 +638,21 @@ std::string PercentageString(double n) { std::string TimeString(double s) { int is = int(s); + int md = 1; + int sd = 1; std::stringstream ss; + ss << std::setfill('0'); if (is >= 3600) { ss << (is / 3600) << "h "; is %= 3600; + md = 2; } if (is >= 60) { - ss << (is / 60) << "m "; + ss << std::setw(md) << (is / 60) << "m "; is %= 60; + sd = 2; } - ss << is << 's'; + ss << std::setw(sd) << is << 's'; return ss.str(); }