From 38db9a31695abef65ebc421f120a05219132b15f Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 18 Dec 2017 13:34:43 +0100 Subject: [PATCH] load universe from file --- assets | 2 +- src/app/Assets.hpp | 12 ++++ src/app/app.cpp | 136 +++++++++++++++++++++++++++++++++++++++ src/app/states.cpp | 2 +- src/blobs.cpp | 47 +------------- src/world/Simulation.hpp | 7 +- src/world/sim.cpp | 15 +++-- tst/app/AssetTest.cpp | 24 ++++++- tst/app/AssetTest.hpp | 6 +- 9 files changed, 193 insertions(+), 58 deletions(-) diff --git a/assets b/assets index 7c4c2fb..ea14b7c 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 7c4c2fb847cfdf25d90d6b2c46442b8cf899a96a +Subproject commit ea14b7c01b5470c7f10eb349f355a6885ea184d4 diff --git a/src/app/Assets.hpp b/src/app/Assets.hpp index 0d725cc..950ad34 100644 --- a/src/app/Assets.hpp +++ b/src/app/Assets.hpp @@ -23,6 +23,12 @@ namespace blobs { namespace io { class TokenStreamReader; } +namespace world { + class Body; + class Planet; + class Simulation; + class Sun; +} namespace app { struct Assets { @@ -80,6 +86,12 @@ struct Assets { void LoadSkinTexture(const std::string &name, graphics::ArrayTexture &, int layer) const; void LoadSkyTexture(const std::string &name, graphics::CubeMap &) const; + void LoadUniverse(const std::string &name, world::Simulation &) const; + world::Body *ReadBody(io::TokenStreamReader &, world::Simulation &) const; + void ReadBodyProperty(const std::string &name, io::TokenStreamReader &, world::Body &, world::Simulation &) const; + void ReadPlanetProperty(const std::string &name, io::TokenStreamReader &, world::Planet &, world::Simulation &) const; + void ReadSunProperty(const std::string &name, io::TokenStreamReader &, world::Sun &, world::Simulation &) const; + }; } diff --git a/src/app/app.cpp b/src/app/app.cpp index 0f50aa7..950eda8 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -6,6 +6,9 @@ #include "../graphics/Viewport.hpp" #include "../io/Token.hpp" #include "../io/TokenStreamReader.hpp" +#include "../world/Planet.hpp" +#include "../world/Simulation.hpp" +#include "../world/Sun.hpp" #include #include @@ -457,5 +460,138 @@ void Assets::LoadSkyTexture(const string &name, graphics::CubeMap &cm) const { SDL_FreeSurface(srf); } +void Assets::LoadUniverse(const string &name, world::Simulation &sim) const { + std::ifstream universe_file(data_path + name); + io::TokenStreamReader universe_reader(universe_file); + ReadBody(universe_reader, sim); + universe_reader.Skip(io::Token::SEMICOLON); +} + +world::Body *Assets::ReadBody(io::TokenStreamReader &in, world::Simulation &sim) const { + std::unique_ptr body; + string name; + in.ReadIdentifier(name); + if (name == "Sun") { + world::Sun *sun = new world::Sun; + body.reset(sun); + sim.AddSun(*sun); + in.Skip(io::Token::ANGLE_BRACKET_OPEN); + while (in.Peek().type != io::Token::ANGLE_BRACKET_CLOSE) { + in.ReadIdentifier(name); + in.Skip(io::Token::EQUALS); + ReadSunProperty(name, in, *sun, sim); + in.Skip(io::Token::SEMICOLON); + } + in.Skip(io::Token::ANGLE_BRACKET_CLOSE); + in.Skip(io::Token::SEMICOLON); + } else if (name == "Planet") { + in.Skip(io::Token::PARENTHESIS_OPEN); + int sidelength = in.GetInt(); + in.Skip(io::Token::PARENTHESIS_CLOSE); + world::Planet *planet = new world::Planet(sidelength); + sim.AddPlanet(*planet); + body.reset(planet); + in.Skip(io::Token::ANGLE_BRACKET_OPEN); + while (in.Peek().type != io::Token::ANGLE_BRACKET_CLOSE) { + in.ReadIdentifier(name); + in.Skip(io::Token::EQUALS); + ReadPlanetProperty(name, in, *planet, sim); + in.Skip(io::Token::SEMICOLON); + } + in.Skip(io::Token::ANGLE_BRACKET_CLOSE); + } else { + throw std::runtime_error("unknown body class " + name); + } + return body.release(); +} + +void Assets::ReadSunProperty(const std::string &name, io::TokenStreamReader &in, world::Sun &sun, world::Simulation &sim) const { + if (name == "color") { + glm::dvec3 color(0.0); + in.ReadVec(color); + sun.Color(color); + } else if (name == "luminosity") { + sun.Luminosity(in.GetDouble()); + } else { + ReadBodyProperty(name, in, sun, sim); + } +} + +void Assets::ReadPlanetProperty(const std::string &name, io::TokenStreamReader &in, world::Planet &planet, world::Simulation &sim) const { + if (name == "generate") { + string gen; + in.ReadIdentifier(gen); + if (gen == "earthlike") { + world::GenerateEarthlike(data.tile_types, planet); + } else if (gen == "test") { + world::GenerateTest(data.tile_types, planet); + } else { + throw std::runtime_error("unknown surface generator " + gen); + } + } else if (name == "atmosphere") { + string atm; + in.ReadIdentifier(atm); + planet.Atmosphere(data.resources[atm].id); + } else { + ReadBodyProperty(name, in, planet, sim); + } +} + +void Assets::ReadBodyProperty(const std::string &name, io::TokenStreamReader &in, world::Body &body, world::Simulation &sim) const { + if (name == "name") { + string value; + in.ReadString(value); + body.Name(value); + } else if (name == "mass") { + body.Mass(in.GetDouble()); + } else if (name == "radius") { + body.Radius(in.GetDouble()); + } else if (name == "axial_tilt") { + glm::dvec2 tilt(0.0); + in.ReadVec(tilt); + body.AxialTilt(tilt); + } else if (name == "rotation") { + body.Rotation(in.GetDouble()); + } else if (name == "angular_momentum") { + body.AngularMomentum(in.GetDouble()); + } else if (name == "orbit") { + in.Skip(io::Token::ANGLE_BRACKET_OPEN); + while (in.Peek().type != io::Token::ANGLE_BRACKET_CLOSE) { + string oname; + in.ReadIdentifier(oname); + in.Skip(io::Token::EQUALS); + if (oname == "SMA" || oname == "semi_major_axis") { + body.GetOrbit().SemiMajorAxis(in.GetDouble()); + } else if (oname == "ECC" || oname == "eccentricity") { + body.GetOrbit().Eccentricity(in.GetDouble()); + } else if (oname == "INC" || oname == "inclination") { + body.GetOrbit().Inclination(in.GetDouble()); + } else if (oname == "ASC" || oname == "ascending_node" || oname == "longitude_ascending") { + body.GetOrbit().LongitudeAscending(in.GetDouble()); + } else if (oname == "ARG" || oname == "APE" || oname == "argument_periapsis") { + body.GetOrbit().ArgumentPeriapsis(in.GetDouble()); + } else if (oname == "MNA" || oname == "mean_anomaly") { + body.GetOrbit().MeanAnomaly(in.GetDouble()); + } else { + throw std::runtime_error("unknown orbit property " + oname); + } + in.Skip(io::Token::SEMICOLON); + } + in.Skip(io::Token::ANGLE_BRACKET_CLOSE); + } else if (name == "children") { + in.Skip(io::Token::BRACKET_OPEN); + while (in.Peek().type != io::Token::BRACKET_CLOSE) { + world::Body *b = ReadBody(in, sim); + b->SetParent(body); + if (in.Peek().type == io::Token::COMMA) { + in.Skip(io::Token::COMMA); + } + } + in.Skip(io::Token::BRACKET_CLOSE); + } else { + throw std::runtime_error("unknown body property " + name); + } +} + } } diff --git a/src/app/states.cpp b/src/app/states.cpp index 3736331..8af5a85 100644 --- a/src/app/states.cpp +++ b/src/app/states.cpp @@ -25,7 +25,7 @@ MasterState::MasterState(Assets &assets, world::Simulation &sim) noexcept : State() , assets(assets) , sim(sim) -, cam(sim.Root()) +, cam(**sim.Suns().begin()) , cam_pos(0.0, 0.0, 1.0) , cam_tgt_pos(0.0, 0.0, 1.0) , cam_focus(0.0) diff --git a/src/blobs.cpp b/src/blobs.cpp index 475c3fa..9562f84 100644 --- a/src/blobs.cpp +++ b/src/blobs.cpp @@ -19,53 +19,12 @@ int main(int argc, char *argv[]) { app::Init init(true, 8); app::Assets assets; - world::Sun sun; - sun.Name("Sun"); - sun.Mass(1.0e17); - sun.Radius(200.0); - sun.Color(glm::dvec3(1.0)); - sun.Luminosity(1.0e8); - sun.AxialTilt(glm::dvec2(PI * 0.25, PI * 0.25)); - sun.AngularMomentum(1.0e18); - - world::Planet planet(25); - planet.Name("Planet"); - planet.SetParent(sun); - planet.Mass(1.0e13); - planet.GetOrbit().SemiMajorAxis(8184.0); - planet.AxialTilt(glm::dvec2(PI * 0.127, 0.0)); - planet.AngularMomentum(6.5e13); - - world::Planet moon(5); - moon.Name("Moon"); - moon.SetParent(planet); - moon.Mass(1.0e7); - moon.GetOrbit().SemiMajorAxis(72.5); - moon.Rotation(PI * 0.25); - moon.AngularMomentum(5.22e5); - - world::Planet second_planet(14); - second_planet.Name("Second planet"); - second_planet.SetParent(sun); - second_planet.Mass(1.0e12); - second_planet.GetOrbit().SemiMajorAxis(4350.0); - second_planet.AxialTilt(glm::dvec2(PI * 0.95, 0.0)); - second_planet.AngularMomentum(1.0e12); - - world::Simulation sim(sun, assets); - sim.AddSun(sun); - sim.AddPlanet(planet); - sim.AddPlanet(second_planet); - sim.AddPlanet(moon); - - world::GenerateEarthlike(assets.data.tile_types, planet); - planet.Atmosphere(assets.data.resources["air"].id); - world::GenerateTest(assets.data.tile_types, moon); - world::GenerateTest(assets.data.tile_types, second_planet); + world::Simulation sim(assets); + assets.LoadUniverse("universe", sim); auto blob = new creature::Creature(sim); blob->Name(assets.name.Sequential()); - Spawn(*blob, planet); + Spawn(*blob, sim.PlanetByName("Planet")); // decrease chances of ur-blob dying without splitting blob->GetProperties().Fertility() = 1.0; blob->BuildVAO(); diff --git a/src/world/Simulation.hpp b/src/world/Simulation.hpp index 3be86a7..3357e52 100644 --- a/src/world/Simulation.hpp +++ b/src/world/Simulation.hpp @@ -25,7 +25,7 @@ class TileType; class Simulation { public: - explicit Simulation(Body &root, app::Assets &); + explicit Simulation(app::Assets &); ~Simulation(); Simulation(const Simulation &) = delete; @@ -37,9 +37,6 @@ public: public: void Tick(double dt); - Body &Root() noexcept { return root; } - const Body &Root() const noexcept { return root; } - app::Assets &Assets() noexcept { return assets; } const app::Assets &Assets() const noexcept { return assets; } const Set &Resources() const noexcept { return assets.data.resources; } @@ -52,6 +49,7 @@ public: const std::set &Bodies() const noexcept { return bodies; } const std::set &Planets() const noexcept { return planets; } const std::set &Suns() const noexcept { return suns; } + Planet &PlanetByName(const std::string &); void SetAlive(creature::Creature *); std::vector &LiveCreatures() noexcept { return alive; } @@ -70,7 +68,6 @@ public: std::ostream &Log(); private: - Body &root; app::Assets &assets; std::set bodies; diff --git a/src/world/sim.cpp b/src/world/sim.cpp index 350d244..8b4ecd4 100644 --- a/src/world/sim.cpp +++ b/src/world/sim.cpp @@ -69,9 +69,8 @@ std::string Record::ValueString(int i) const { } } -Simulation::Simulation(Body &r, app::Assets &assets) -: root(r) -, assets(assets) +Simulation::Simulation(app::Assets &assets) +: assets(assets) , bodies() , planets() , suns() @@ -79,7 +78,6 @@ Simulation::Simulation(Body &r, app::Assets &assets) , dead() , time(0.0) , records(7) { - AddBody(r); records[0].name = "Age"; records[0].type = Record::TIME; records[1].name = "Mass"; @@ -126,6 +124,15 @@ void Simulation::AddSun(Sun &s) { suns.insert(&s); } +Planet &Simulation::PlanetByName(const std::string &name) { + for (auto &p : planets) { + if (p->Name() == name) { + return *p; + } + } + throw std::runtime_error("planet named \"" + name + "\" not found"); +} + void Simulation::SetAlive(creature::Creature *c) { alive.push_back(c); } diff --git a/tst/app/AssetTest.cpp b/tst/app/AssetTest.cpp index d6b5a0e..2bd132f 100644 --- a/tst/app/AssetTest.cpp +++ b/tst/app/AssetTest.cpp @@ -2,6 +2,7 @@ #include "app/Assets.hpp" #include "app/init.hpp" +#include "world/Simulation.hpp" CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(blobs::app::test::AssetTest, "headed"); @@ -17,7 +18,7 @@ void AssetTest::tearDown() { } -void AssetTest::testLoadAll() { +void AssetTest::testLoadBasic() { Init init(false, 1); Assets assets; @@ -70,6 +71,27 @@ void AssetTest::testLoadAll() { ); } +void AssetTest::testLoadUniverse() { + Init init(false, 1); + Assets assets; + + world::Simulation sim(assets); + assets.LoadUniverse("universe", sim); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong number of suns in default universe", + std::set::size_type(1), sim.Suns().size() + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong number of planets in default universe", + std::set::size_type(3), sim.Planets().size() + ); + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "spawn planet does not exist", + sim.PlanetByName("Planet") + ); +} + } } } diff --git a/tst/app/AssetTest.hpp b/tst/app/AssetTest.hpp index fa158bf..9fbe728 100644 --- a/tst/app/AssetTest.hpp +++ b/tst/app/AssetTest.hpp @@ -13,7 +13,8 @@ class AssetTest CPPUNIT_TEST_SUITE(AssetTest); -CPPUNIT_TEST(testLoadAll); +CPPUNIT_TEST(testLoadBasic); +CPPUNIT_TEST(testLoadUniverse); CPPUNIT_TEST_SUITE_END(); @@ -21,7 +22,8 @@ public: void setUp(); void tearDown(); - void testLoadAll(); + void testLoadBasic(); + void testLoadUniverse(); }; -- 2.39.2