X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fworld%2Fworld.cpp;h=a939b3e586e129e748984e0c55ef9386701ea95d;hb=02d5571eef7630c38968af264a441aa43e802d0f;hp=b872503c185b928df0d6175a0eb059c3518cbde6;hpb=ed63638006af93bf0cf010ed48706b893ac0da35;p=blobs.git diff --git a/src/world/world.cpp b/src/world/world.cpp index b872503..a939b3e 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -4,15 +4,21 @@ #include "Simulation.hpp" #include "Sun.hpp" #include "Tile.hpp" +#include "TileSet.hpp" +#include "TileType.hpp" #include "../const.hpp" #include "../app/Assets.hpp" #include "../graphics/Viewport.hpp" +#include "../rand/OctaveNoise.hpp" +#include "../rand/SimplexNoise.hpp" #include #include +#include #include #include +#include #include using blobs::G; @@ -258,7 +264,15 @@ Planet::Planet(int sidelength) Planet::~Planet() { } -void Planet::BuildVAOs() { +glm::dvec3 Planet::TileCenter(int surface, int x, int y) const noexcept { + glm::dvec3 center(0.0f); + center[(surface + 0) % 3] = x + 0.5 - Radius(); + center[(surface + 1) % 3] = y + 0.5 - Radius(); + center[(surface + 2) % 3] = surface < 3 ? Radius() : -Radius(); + return center; +} + +void Planet::BuildVAOs(const TileSet &ts) { vao.Bind(); vao.BindAttributes(); vao.EnableAttribute(0); @@ -268,7 +282,7 @@ void Planet::BuildVAOs() { vao.ReserveAttributes(TilesTotal() * 4, GL_STATIC_DRAW); { auto attrib = vao.MapAttributes(GL_WRITE_ONLY); - float offset = sidelength * 0.5f; + float offset = Radius(); // srf 0 1 2 3 4 5 // up +Z +X +Y -Z -X -Y @@ -276,7 +290,7 @@ void Planet::BuildVAOs() { for (int index = 0, surface = 0; surface < 6; ++surface) { for (int y = 0; y < sidelength; ++y) { for (int x = 0; x < sidelength; ++x, ++index) { - float tex = TileAt(surface, x, y).type; + float tex = ts[TileAt(surface, x, y).type].texture; const float tex_u_begin = surface < 3 ? 1.0f : 0.0f; const float tex_u_end = surface < 3 ? 0.0f : 1.0f; attrib[4 * index + 0].position[(surface + 0) % 3] = x + 0 - offset; @@ -361,7 +375,56 @@ void Planet::Draw(app::Assets &assets, graphics::Viewport &viewport) { } -void GenerateTest(Planet &p) { +void GenerateEarthlike(const TileSet &tiles, Planet &p) noexcept { + rand::SimplexNoise elevation_gen(0); + + const int ice = tiles["ice"].id; + const int grass = tiles["grass"].id; + const int water = tiles["water"].id; + const int sand = tiles["sand"].id; + const int rock = tiles["rock"].id; + + constexpr double water_thresh = 0.0; + constexpr double beach_thresh = 0.1; + constexpr double mountain_thresh = 0.5; + + const glm::dvec3 axis(glm::dvec4(0.0, 1.0, 0.0, 0.0) * glm::eulerAngleXY(p.SurfaceTilt().x, p.SurfaceTilt().y)); + const double cap_thresh = std::cos(p.AxialTilt().x); + + for (int surface = 0; surface <= 5; ++surface) { + for (int y = 0; y < p.SideLength(); ++y) { + for (int x = 0; x < p.SideLength(); ++x) { + glm::dvec3 to_tile = p.TileCenter(surface, x, y); + double near_axis = std::abs(glm::dot(glm::normalize(to_tile), axis)); + if (near_axis > cap_thresh) { + p.TileAt(surface, x, y).type = ice; + continue; + } + float elevation = rand::OctaveNoise( + elevation_gen, + to_tile / p.Radius(), + 3, // octaves + 0.5, // persistence + 2 / p.Radius(), // frequency + 2, // amplitude + 2 // growth + ); + if (elevation < water_thresh) { + p.TileAt(surface, x, y).type = water; + } else if (elevation < beach_thresh) { + p.TileAt(surface, x, y).type = sand; + } else if (elevation < mountain_thresh) { + p.TileAt(surface, x, y).type = grass; + } else { + p.TileAt(surface, x, y).type = rock; + } + } + } + } + p.BuildVAOs(tiles); +} + +void GenerateTest(const TileSet &tiles, Planet &p) noexcept { for (int surface = 0; surface <= 5; ++surface) { for (int y = 0; y < p.SideLength(); ++y) { for (int x = 0; x < p.SideLength(); ++x) { @@ -373,7 +436,7 @@ void GenerateTest(Planet &p) { } } } - p.BuildVAOs(); + p.BuildVAOs(tiles); } @@ -384,5 +447,41 @@ Sun::Sun() Sun::~Sun() { } +TileSet::TileSet() +: types() +, names() { +} + +TileSet::~TileSet() { +} + +int TileSet::Add(const TileType &t) { + int id = types.size(); + if (!names.emplace(t.name, id).second) { + throw std::runtime_error("duplicate tile type name " + t.name); + } + types.emplace_back(t); + types.back().id = id; + return id; +} + +TileType &TileSet::operator [](const std::string &name) { + auto entry = names.find(name); + if (entry != names.end()) { + return types[entry->second]; + } else { + throw std::runtime_error("unknown tile type " + name); + } +} + +const TileType &TileSet::operator [](const std::string &name) const { + auto entry = names.find(name); + if (entry != names.end()) { + return types[entry->second]; + } else { + throw std::runtime_error("unknown tile type " + name); + } +} + } }