]> git.localhorst.tv Git - blobs.git/commitdiff
spherical planets
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 6 Dec 2017 21:27:58 +0000 (22:27 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 6 Dec 2017 23:10:05 +0000 (00:10 +0100)
15 files changed:
src/app/app.cpp
src/app/states.cpp
src/blobs.cpp
src/creature/LocateResourceGoal.hpp
src/creature/Memory.hpp
src/creature/Situation.hpp
src/creature/creature.cpp
src/creature/goal.cpp
src/graphics/Camera.hpp
src/graphics/PlanetSurface.hpp
src/graphics/shader.cpp
src/graphics/viewport.cpp
src/world/Planet.hpp
src/world/world.cpp
tst/world/PlanetTest.cpp

index 3f87c8f5cf39011e0734d936bf315e1be7ababdb..913f9f265dc7cffbf7228b24402bb5d621696555 100644 (file)
@@ -176,7 +176,7 @@ Assets::Assets()
 , font_path(path + "fonts/")
 , skin_path(path + "skins/")
 , tile_path(path + "tiles/")
-, random(0x6283B64CEFE47925)
+, random(0x6283B64CEFE57925)
 , fonts{
        graphics::Font(font_path + "DejaVuSans.ttf", 32),
        graphics::Font(font_path + "DejaVuSans.ttf", 24),
index 4951c9f220c5afe1308b13e504ed33d981d068e6..92879b4683bc724a5cbd23e35d1bc973cdbb9d0c 100644 (file)
@@ -109,7 +109,7 @@ void MasterState::OnMouseMotion(const SDL_MouseMotionEvent &e) {
        constexpr double pitch_scale = PI * 0.001;
        constexpr double yaw_scale = PI * 0.002;
        if (cam_dragging) {
-               cam_orient.x = glm::clamp(cam_orient.x + double(e.yrel) * pitch_scale, 0.0, PI * 0.5);
+               cam_orient.x = glm::clamp(cam_orient.x + double(e.yrel) * pitch_scale, 0.0, PI * 0.499);
                cam_orient.y = std::fmod(cam_orient.y + double(e.xrel) * yaw_scale, PI * 2.0);
        }
 }
index 01bfb2a8ed7c1fd8c8aa99207c752a2966b49f45..1d854fc403df7ae6f20258f1ef096fd9616f8b78 100644 (file)
@@ -13,7 +13,6 @@
 #include <cstdint>
 #include <iostream>
 
-
 using namespace blobs;
 
 namespace {
@@ -98,22 +97,6 @@ int main(int argc, char *argv[]) {
        blob->BuildVAO();
 
        app::MasterState state(assets, sim);
-       state.GetCamera()
-               .Reference(planet)
-               // sunrise
-               //.FirstPerson(0, glm::vec3(0.0f, 0.0f, 0.1f), glm::vec3(1.0f, -0.75f, 0.1f))
-               // sunset
-               //.FirstPerson(3, glm::vec3(0.0f, 0.0f, 0.1f), glm::vec3(1.0f, -0.75f, 0.1f))
-               // from afar
-               .MapView(0, glm::vec3(0.0f, 0.0f, 30.0f), 0.0f)
-               // from afar, rotating
-               //.Orbital(glm::vec3(-60.0f, 0.0f, 0.0f))
-       ;
-       // system view
-       //state.GetCamera()
-       //      .Reference(sun)
-       //      .Orbital(glm::vec3(-500.0f, 500.0f, 500.0f))
-       //;
        state.GetCreaturePanel().Show(*blob);
        state.GetTimePanel().SetBody(planet);
 
index f0937c93c3e00d4f92109864b806438565226e97..c87f4f18a07b47712ca8ea776139288de1c11e16 100644 (file)
@@ -26,14 +26,12 @@ public:
 private:
        void LocateResource();
        void SearchVicinity();
-       bool OnTargetTile() const noexcept;
+       bool NearTarget() const noexcept;
 
 private:
        Composition accept;
        bool found;
        glm::dvec3 target_pos;
-       int target_srf;
-       glm::ivec2 target_tile;
        bool searching;
        double reevaluate;
 
index 3bc39082b0741017ecae5bebcb69fd8776867eb8..c58fd26420576067d0688df153da1b5b0b6dd5df 100644 (file)
@@ -19,8 +19,7 @@ class Memory {
 public:
        struct Location {
                world::Planet *planet;
-               int surface;
-               glm::ivec2 coords;
+               glm::dvec3 position;
        };
 
 public:
index 4d635f5e8ba223ba94225df3b2701ccd4767485c..25d218ddc2635d08bd26917df55623aa7082c23f 100644 (file)
@@ -53,10 +53,7 @@ public:
        bool OnPlanet() const noexcept;
        world::Planet &GetPlanet() const noexcept { return *planet; }
        bool OnSurface() const noexcept;
-       int Surface() const noexcept { return surface; }
        const glm::dvec3 &Position() const noexcept { return state.pos; }
-       bool OnTile() const noexcept;
-       glm::ivec2 SurfacePosition() const noexcept;
        world::Tile &GetTile() const noexcept;
        const world::TileType &GetTileType() const noexcept;
 
@@ -72,12 +69,11 @@ public:
        void Heading(const glm::dvec3 &h) noexcept { state.dir = h; }
        const glm::dvec3 &Heading() const noexcept { return state.dir; }
 
-       void SetPlanetSurface(world::Planet &, int srf, const glm::dvec3 &pos) noexcept;
+       void SetPlanetSurface(world::Planet &, const glm::dvec3 &pos) noexcept;
 
 public:
        world::Planet *planet;
        State state;
-       int surface;
        enum {
                LOST,
                PLANET_SURFACE,
index d7a9724fbe62474884cf9538165efbac1df73b81..a9c4dc73c613312e18da52b3a2ead77ddc827643 100644 (file)
@@ -399,7 +399,7 @@ void Creature::TickState(double dt) {
                if (ang < turn_rate) {
                        state.dir = normalize(state.vel);
                } else if (std::abs(ang - PI) < 0.001) {
-                       state.dir = rotate(state.dir, turn_rate, world::Planet::SurfaceNormal(situation.Surface()));
+                       state.dir = rotate(state.dir, turn_rate, situation.GetPlanet().NormalAt(state.pos));
                } else {
                        state.dir = rotate(state.dir, turn_rate, normalize(cross(state.dir, nvel)));
                }
@@ -415,8 +415,8 @@ Situation::Derivative Creature::Step(const Situation::Derivative &ds, double dt)
        s.vel += ds.acc * dt;
        glm::dvec3 force(steering.Force(s));
        // gravity = antinormal * mass * Gm / r²
-       double elevation = s.pos[(situation.Surface() + 2) % 3];
-       glm::dvec3 normal(world::Planet::SurfaceNormal(situation.Surface()));
+       double elevation = situation.GetPlanet().DistanceAt(s.pos);
+       glm::dvec3 normal(situation.GetPlanet().NormalAt(s.pos));
        force += glm::dvec3(
                -normal
                * Mass() * situation.GetPlanet().GravitationalParameter()
@@ -491,10 +491,16 @@ math::AABB Creature::CollisionBox() const noexcept {
 glm::dmat4 Creature::CollisionTransform() const noexcept {
        const double half_size = size * 0.5;
        const glm::dvec3 &pos = situation.Position();
-       const glm::dmat3 srf(world::Planet::SurfaceOrientation(situation.Surface()));
+       glm::dmat3 orient;
+       orient[1] = situation.GetPlanet().NormalAt(pos);
+       orient[2] = situation.Heading();
+       if (std::abs(dot(orient[1], orient[2])) > 0.999) {
+               orient[2] = glm::dvec3(orient[1].z, orient[1].x, orient[1].y);
+       }
+       orient[0] = normalize(cross(orient[1], orient[2]));
+       orient[2] = normalize(cross(orient[0], orient[1]));
        return glm::translate(glm::dvec3(pos.x, pos.y, pos.z + half_size))
-               * glm::rotate(glm::orientedAngle(-srf[2], situation.Heading(), srf[1]), srf[1])
-               * glm::dmat4(srf);
+               * glm::dmat4(orient);
 }
 
 glm::dmat4 Creature::LocalTransform() noexcept {
@@ -599,8 +605,8 @@ void Creature::Draw(graphics::Viewport &viewport) {
 
 void Spawn(Creature &c, world::Planet &p) {
        p.AddCreature(&c);
-       c.GetSituation().SetPlanetSurface(p, 0, p.TileCenter(0, p.SideLength() / 2, p.SideLength() / 2));
-       c.GetSituation().Heading(-world::Planet::SurfaceOrientation(0)[2]);
+       c.GetSituation().SetPlanetSurface(p, glm::dvec3(0.0, 0.0, p.Radius()));
+       c.GetSituation().Heading(glm::dvec3(1.0, 0.0, 0.0));
 
        // probe surrounding area for common resources
        int start = p.SideLength() / 2 - 2;
@@ -718,7 +724,7 @@ void Split(Creature &c) {
        s.GetPlanet().AddCreature(a);
        // TODO: duplicate situation somehow
        a->GetSituation().SetPlanetSurface(
-               s.GetPlanet(), s.Surface(),
+               s.GetPlanet(),
                s.Position() + glm::dvec3(0.0, 0.55 * a->Size(), 0.0));
        a->BuildVAO();
        c.GetSimulation().Log() << a->Name() << " was born" << std::endl;
@@ -732,7 +738,7 @@ void Split(Creature &c) {
        }
        s.GetPlanet().AddCreature(b);
        b->GetSituation().SetPlanetSurface(
-               s.GetPlanet(), s.Surface(),
+               s.GetPlanet(),
                s.Position() - glm::dvec3(0.0, 0.55 * b->Size(), 0.0));
        b->BuildVAO();
        c.GetSimulation().Log() << b->Name() << " was born" << std::endl;
@@ -754,13 +760,13 @@ void Memory::Erase() {
 
 void Memory::Tick(double dt) {
        Situation &s = c.GetSituation();
-       if (s.OnTile()) {
-               TrackStay({ &s.GetPlanet(), s.Surface(), s.SurfacePosition() }, dt);
+       if (s.OnSurface()) {
+               TrackStay({ &s.GetPlanet(), s.Position() }, dt);
        }
 }
 
 void Memory::TrackStay(const Location &l, double t) {
-       const world::TileType &type = l.planet->TypeAt(l.surface, l.coords.x, l.coords.y);
+       const world::TileType &type = l.planet->TileTypeAt(l.position);
        auto entry = known_types.find(type.id);
        if (entry != known_types.end()) {
                if (c.GetSimulation().Time() - entry->second.last_been > c.GetProperties().Lifetime() * 0.1) {
@@ -808,7 +814,6 @@ std::string NameGenerator::Sequential() {
 Situation::Situation()
 : planet(nullptr)
 , state(glm::dvec3(0.0), glm::dvec3(0.0))
-, surface(0)
 , type(LOST) {
 }
 
@@ -823,25 +828,12 @@ bool Situation::OnSurface() const noexcept {
        return type == PLANET_SURFACE;
 }
 
-bool Situation::OnTile() const noexcept {
-       if (type != PLANET_SURFACE) return false;
-       glm::ivec2 t(planet->SurfacePosition(surface, state.pos));
-       return t.x >= 0 && t.x < planet->SideLength()
-               && t.y >= 0 && t.y < planet->SideLength();
-}
-
-glm::ivec2 Situation::SurfacePosition() const noexcept {
-       return planet->SurfacePosition(surface, state.pos);
-}
-
 world::Tile &Situation::GetTile() const noexcept {
-       glm::ivec2 t(planet->SurfacePosition(surface, state.pos));
-       return planet->TileAt(surface, t.x, t.y);
+       return planet->TileAt(state.pos);
 }
 
 const world::TileType &Situation::GetTileType() const noexcept {
-       glm::ivec2 t(planet->SurfacePosition(surface, state.pos));
-       return planet->TypeAt(surface, t.x, t.y);
+       return planet->TileTypeAt(state.pos);
 }
 
 void Situation::Move(const glm::dvec3 &dp) noexcept {
@@ -856,24 +848,16 @@ void Situation::Accelerate(const glm::dvec3 &dv) noexcept {
 
 void Situation::EnforceConstraints(State &s) noexcept {
        if (OnSurface()) {
-               if (Surface() < 3) {
-                       if (s.pos[(Surface() + 2) % 3] < GetPlanet().Radius()) {
-                               s.pos[(Surface() + 2) % 3] = GetPlanet().Radius();
-                               s.vel[(Surface() + 2) % 3] = std::max(0.0, s.vel[(Surface() + 2) % 3]);
-                       }
-               } else {
-                       if (s.pos[(Surface() + 2) % 3] > -GetPlanet().Radius()) {
-                               s.pos[(Surface() + 2) % 3] = -GetPlanet().Radius();
-                               s.vel[(Surface() + 2) % 3] = std::min(0.0, s.vel[(Surface() + 2) % 3]);
-                       }
+               double r = GetPlanet().Radius();
+               if (length2(s.pos) < r * r) {
+                       s.pos = normalize(s.pos) * r;
                }
        }
 }
 
-void Situation::SetPlanetSurface(world::Planet &p, int srf, const glm::dvec3 &pos) noexcept {
+void Situation::SetPlanetSurface(world::Planet &p, const glm::dvec3 &pos) noexcept {
        type = PLANET_SURFACE;
        planet = &p;
-       surface = srf;
        state.pos = pos;
        EnforceConstraints(state);
 }
index 3f61e2e8b80214571a75753f5581611ffa970d2c..4124876851ba160e433442c0c756b33027f1a6cb 100644 (file)
@@ -219,7 +219,7 @@ void IngestGoal::Action() {
 }
 
 bool IngestGoal::OnSuitableTile() {
-       if (!GetSituation().OnTile()) {
+       if (!GetSituation().OnSurface()) {
                return false;
        }
        const world::TileType &t = GetSituation().GetTileType();
@@ -315,8 +315,6 @@ LocateResourceGoal::LocateResourceGoal(Creature &c)
 , accept()
 , found(false)
 , target_pos(0.0)
-, target_srf(0)
-, target_tile(0)
 , searching(false)
 , reevaluate(0.0) {
 }
@@ -355,7 +353,7 @@ void LocateResourceGoal::Action() {
                                GetSteering().GoTo(target_pos);
                        }
                }
-       } else if (OnTargetTile()) {
+       } else if (NearTarget()) {
                GetSteering().Halt();
                if (!GetSituation().Moving()) {
                        SetComplete();
@@ -367,7 +365,7 @@ void LocateResourceGoal::Action() {
 }
 
 void LocateResourceGoal::LocateResource() {
-       if (GetSituation().OnTile()) {
+       if (GetSituation().OnSurface()) {
                const world::TileType &t = GetSituation().GetTileType();
                auto yield = t.FindBestResource(accept);
                if (yield != t.resources.cend()) {
@@ -376,8 +374,6 @@ void LocateResourceGoal::LocateResource() {
                        found = true;
                        searching = false;
                        target_pos = GetSituation().Position();
-                       target_srf = GetSituation().Surface();
-                       target_tile = GetSituation().GetPlanet().SurfacePosition(target_srf, target_pos);
                } else {
                        // go find somewhere else
                        SearchVicinity();
@@ -391,51 +387,52 @@ void LocateResourceGoal::LocateResource() {
 
 void LocateResourceGoal::SearchVicinity() {
        const world::Planet &planet = GetSituation().GetPlanet();
-       int srf = GetSituation().Surface();
        const glm::dvec3 &pos = GetSituation().Position();
+       const glm::dvec3 normal(planet.NormalAt(pos));
+       const glm::dvec3 step_x(normalize(cross(normal, glm::dvec3(normal.z, normal.x, normal.y))));
+       const glm::dvec3 step_y(normalize(cross(step_x, normal)));
 
-       glm::ivec2 loc = planet.SurfacePosition(srf, pos);
-       glm::ivec2 seek_radius(2);
-       glm::ivec2 begin(glm::max(glm::ivec2(0), loc - seek_radius));
-       glm::ivec2 end(glm::min(glm::ivec2(planet.SideLength()), loc + seek_radius + glm::ivec2(1)));
-
-       double rating[end.y - begin.y][end.x - begin.x];
-       std::memset(rating, 0, sizeof(double) * (end.y - begin.y) * (end.x - begin.x));
+       constexpr int search_radius = 2;
+       double rating[2 * search_radius + 1][2 * search_radius + 1] = {0};
 
        // find close and rich field
-       for (int y = begin.y; y < end.y; ++y) {
-               for (int x = begin.x; x < end.x; ++x) {
-                       const world::TileType &type = planet.TypeAt(srf, x, y);
+       for (int y = -search_radius; y < search_radius + 1; ++y) {
+               for (int x = -search_radius; x < search_radius + 1; ++x) {
+                       const glm::dvec3 tpos(pos + (double(x) * step_x) + (double(y) * step_y));
+                       if (!GetCreature().PerceptionTest(tpos)) continue;
+                       const world::TileType &type = planet.TileTypeAt(tpos);
                        auto yield = type.FindBestResource(accept);
                        if (yield != type.resources.cend()) {
-                               glm::dvec3 tc(planet.TileCenter(srf, x, y));
-                               if (!GetCreature().PerceptionTest(tc)) continue;
                                // TODO: subtract minimum yield
-                               rating[y - begin.y][x - begin.x] = yield->ubiquity * accept.Get(yield->resource);
-                               double dist = std::max(0.125, 0.25 * glm::length(tc - pos));
-                               rating[y - begin.y][x - begin.x] /= dist;
+                               rating[y + search_radius][x + search_radius] = yield->ubiquity * accept.Get(yield->resource);
+                               // penalize distance
+                               double dist = std::max(0.125, 0.25 * glm::length(tpos - pos));
+                               rating[y + search_radius][x + search_radius] /= dist;
                        }
                }
        }
 
-       // demote crowded tiles
+       // penalize crowding
        for (auto &c : planet.Creatures()) {
                if (&*c == &GetCreature()) continue;
-               if (c->GetSituation().Surface() != srf) continue;
-               glm::ivec2 coords(c->GetSituation().SurfacePosition());
-               if (coords.x < begin.x || coords.x >= end.x) continue;
-               if (coords.y < begin.y || coords.y >= end.y) continue;
-               rating[coords.y - begin.y][coords.x - begin.x] *= 0.8;
+               for (int y = -search_radius; y < search_radius + 1; ++y) {
+                       for (int x = -search_radius; x < search_radius + 1; ++x) {
+                               const glm::dvec3 tpos(pos + (double(x) * step_x) + (double(y) * step_y));
+                               if (length2(tpos - c->GetSituation().Position()) < 1.0) {
+                                       rating[y + search_radius][x + search_radius] *= 0.8;
+                               }
+                       }
+               }
        }
 
        glm::ivec2 best_pos(0);
        double best_rating = -1.0;
 
-       for (int y = begin.y; y < end.y; ++y) {
-               for (int x = begin.x; x < end.x; ++x) {
-                       if (rating[y - begin.y][x - begin.x] > best_rating) {
+       for (int y = -search_radius; y < search_radius + 1; ++y) {
+               for (int x = -search_radius; x < search_radius + 1; ++x) {
+                       if (rating[y + search_radius][x + search_radius] > best_rating) {
                                best_pos = glm::ivec2(x, y);
-                               best_rating = rating[y - begin.y][x - begin.x];
+                               best_rating = rating[y + search_radius][x + search_radius];
                        }
                }
        }
@@ -443,29 +440,24 @@ void LocateResourceGoal::SearchVicinity() {
        if (best_rating) {
                found = true;
                searching = false;
-               target_pos = planet.TileCenter(srf, best_pos.x, best_pos.y);
-               target_srf = srf;
-               target_tile = best_pos;
+               target_pos = normalize(pos + (double(best_pos.x) * step_x) + (double(best_pos.y) * step_y)) * planet.Radius();
                GetSteering().GoTo(target_pos);
        } else if (!searching) {
                found = false;
                searching = true;
                target_pos = GetSituation().Position();
-               target_pos[(srf + 0) % 3] += Assets().random.SNorm();
-               target_pos[(srf + 1) % 3] += Assets().random.SNorm();
+               target_pos += Assets().random.SNorm() * step_x;
+               target_pos += Assets().random.SNorm() * step_y;
                // bias towards current heading
                target_pos += GetSituation().Heading() * 0.5;
-               target_pos = clamp(target_pos, -planet.Radius(), planet.Radius());
+               target_pos = normalize(target_pos) * planet.Radius();
                GetSteering().GoTo(target_pos);
        }
 }
 
-bool LocateResourceGoal::OnTargetTile() const noexcept {
+bool LocateResourceGoal::NearTarget() const noexcept {
        const Situation &s = GetSituation();
-       return s.OnSurface()
-               && s.Surface() == target_srf
-               && s.OnTile()
-               && s.SurfacePosition() == target_tile;
+       return s.OnSurface() && length2(s.Position() - target_pos) < 0.5;
 }
 
 }
index 163291673a0f6a5a05786309d69eceef73b07bd2..e4c0b7fce04ddc37841a78ab57f6d667140ddc84 100644 (file)
@@ -34,15 +34,8 @@ public:
        const world::Body &Reference() const noexcept { return *ref; }
        Camera &Reference(const world::Body &) noexcept;
 
-       /// standing on given surface, with pos.z being elevation over NN
-       /// looking at given coordinates
-       Camera &FirstPerson(int surface, const glm::vec3 &pos, const glm::vec3 &at) noexcept;
-       /// looking straight down at surface from above
-       Camera &MapView(int surface, const glm::vec3 &pos, float roll = 0.0f) noexcept;
        /// look at center, position relative to orbital reference plane for children
        Camera &Orbital(const glm::vec3 &pos) noexcept;
-       /// look at creature from above
-       Camera &TopDown(const creature::Creature &, double distance, double roll = 0.0f);
        /// look at creature from the side, angle in euler (ZXY in surface reference plane)
        Camera &Radial(const creature::Creature &, double distance, const glm::dvec3 &angle);
 
index b915283d2bdc6453fb8db5dc810d6ca8385f0578..27bd2bc616f703a3c6823a854f583a25bfdcdd07 100644 (file)
@@ -31,7 +31,6 @@ public:
        void SetV(const glm::mat4 &v) noexcept;
        void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept;
        void SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept;
-       void SetNormal(const glm::vec3 &) noexcept;
        void SetTexture(ArrayTexture &) noexcept;
        void SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept;
        void SetNumLights(int n) noexcept;
@@ -57,7 +56,6 @@ private:
        GLuint mv_handle;
        GLuint mvp_handle;
        GLuint sampler_handle;
-       GLuint normal_handle;
 
        GLuint num_lights_handle;
        GLuint light_handle[MAX_LIGHTS * 3];
index 0890dfdc8d308bf84f1de0c47db381bc35fca1e5..b896cfdc323cabf2db7e95a09063599d995d2b5d 100644 (file)
@@ -190,18 +190,21 @@ PlanetSurface::PlanetSurface()
                "#version 330 core\n"
 
                "layout(location = 0) in vec3 vtx_position;\n"
-               "layout(location = 1) in vec3 vtx_tex_uv;\n"
+               "layout(location = 1) in vec3 vtx_normal;\n"
+               "layout(location = 2) in vec3 vtx_tex_uv;\n"
 
                "uniform mat4 M;\n"
                "uniform mat4 MV;\n"
                "uniform mat4 MVP;\n"
 
-               "out vec3 frag_tex_uv;\n"
                "out vec3 vtx_viewspace;\n"
+               "out vec3 nrm_viewspace;\n"
+               "out vec3 frag_tex_uv;\n"
 
                "void main() {\n"
-                       "gl_Position = MVP * vec4(vtx_position, 1);\n"
-                       "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
+                       "gl_Position = MVP * vec4(vtx_position, 1.0);\n"
+                       "vtx_viewspace = (MV * vec4(vtx_position, 1.0)).xyz;\n"
+                       "nrm_viewspace = (MV * vec4(vtx_position, 0.0)).xyz;\n"
                        "frag_tex_uv = vtx_tex_uv;\n"
                "}\n"
        );
@@ -216,16 +219,17 @@ PlanetSurface::PlanetSurface()
                "};\n"
 
                "in vec3 vtx_viewspace;\n"
+               "in vec3 nrm_viewspace;\n"
                "in vec3 frag_tex_uv;\n"
 
                "uniform sampler2DArray tex_sampler;\n"
-               "uniform vec3 normal;\n"
                "uniform int num_lights;\n"
                "uniform LightSource light[8];\n"
 
                "out vec3 color;\n"
 
                "void main() {\n"
+                       "vec3 normal = normalize(nrm_viewspace);\n"
                        "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
                        "vec3 total_light = tex_color * vec3(0.1, 0.1, 0.1);\n"
                        "for (int i = 0; i < num_lights; ++i) {\n"
@@ -253,7 +257,6 @@ PlanetSurface::PlanetSurface()
        mv_handle = prog.UniformLocation("MV");
        mvp_handle = prog.UniformLocation("MVP");
        sampler_handle = prog.UniformLocation("tex_sampler");
-       normal_handle = prog.UniformLocation("normal");
        num_lights_handle = prog.UniformLocation("num_lights");
        for (int i = 0; i < MAX_LIGHTS; ++i) {
                light_handle[3 * i + 0]  = prog.UniformLocation("light[" + std::to_string(i) + "].position");
@@ -310,10 +313,6 @@ void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::
        prog.Uniform(mvp_handle, mvp);
 }
 
-void PlanetSurface::SetNormal(const glm::vec3 &n) noexcept {
-       prog.Uniform(normal_handle, n);
-}
-
 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
        glActiveTexture(GL_TEXTURE0);
        tex.Bind();
index 286fe517e47615342a4293d6ed2cc723658413fa..1e7ea4be21f28dfd0e8a38a38594141bfeab5bc8 100644 (file)
@@ -60,66 +60,12 @@ Camera &Camera::Reference(const world::Body &r) noexcept {
        return *this;
 }
 
-Camera &Camera::FirstPerson(int srf, const glm::vec3 &pos, const glm::vec3 &at) noexcept {
-       track_orient = true;
-
-       float dir = srf < 3 ? 1.0f : -1.0f;
-
-       glm::vec3 position;
-       position[(srf + 0) % 3] = pos.x;
-       position[(srf + 1) % 3] = pos.y;
-       position[(srf + 2) % 3] = dir * (pos.z + Reference().Radius());
-
-       glm::vec3 up(world::Planet::SurfaceNormal(srf));
-
-       glm::vec3 target;
-       target[(srf + 0) % 3] = at.x;
-       target[(srf + 1) % 3] = at.y;
-       target[(srf + 2) % 3] = dir * (at.z + Reference().Radius());
-
-       view = glm::lookAt(position, target, up);
-
-       return *this;
-}
-
-Camera &Camera::MapView(int srf, const glm::vec3 &pos, float roll) noexcept {
-       track_orient = true;
-
-       float dir = srf < 3 ? 1.0f : -1.0f;
-
-       glm::vec3 up(0.0f);
-       up[(srf + 0) % 3] = std::sin(roll);
-       up[(srf + 1) % 3] = std::cos(roll);
-       up[(srf + 2) % 3] = 0.0f;
-
-       glm::vec3 target = pos;
-       target[(srf + 2) % 3] -= dir;
-
-       view = glm::lookAt(pos, target, up);
-
-       return *this;
-}
-
 Camera &Camera::Orbital(const glm::vec3 &pos) noexcept {
        track_orient = false;
        view = glm::lookAt(pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        return *this;
 }
 
-Camera &Camera::TopDown(const creature::Creature &c, double distance, double roll) {
-       const creature::Situation &s = c.GetSituation();
-       if (s.OnSurface()) {
-               int srf = s.Surface();
-               glm::vec3 pos(s.Position() + (world::Planet::SurfaceNormal(srf) * distance));
-               Reference(s.GetPlanet());
-               return MapView(srf, pos, roll);
-       } else {
-               glm::vec3 pos(s.Position());
-               pos += glm::normalize(pos) * float(distance);
-               return Orbital(pos);
-       }
-}
-
 Camera &Camera::Radial(const creature::Creature &c, double distance, const glm::dvec3 &angle) {
        const creature::Situation &s = c.GetSituation();
        glm::dvec3 pos(s.Position());
@@ -128,10 +74,10 @@ Camera &Camera::Radial(const creature::Creature &c, double distance, const glm::
        if (s.OnSurface()) {
                Reference(s.GetPlanet());
                track_orient = true;
-               int srf = s.Surface();
-               up = world::Planet::SurfaceNormal(srf);
+               up = s.GetPlanet().NormalAt(s.Position());
+               glm::dvec3 ref(normalize(cross(up, glm::dvec3(up.z, up.x, up.y))));
                dir =
-                       world::Planet::SurfaceOrientation(srf)
+                       glm::dmat3(ref, up, cross(ref, up))
                        * glm::dmat3(glm::eulerAngleYX(-angle.y, -angle.x))
                        * dir;
        } else {
index 7ac6b570256f7b256679b067ca8887489a4c3c59..237159994c47da1c9dbd1e23bd235ffd2214cbb0 100644 (file)
@@ -35,16 +35,33 @@ public:
        Planet &operator =(Planet &&) = delete;
 
 public:
+       /// surface normal
+       glm::dvec3 NormalAt(const glm::dvec3 &p) const noexcept { return normalize(p); }
+       /// height over surface
+       double ElevationAt(const glm::dvec3 &p) const noexcept { return length(p) - Radius(); }
+       /// distance to planet center
+       double DistanceAt(const glm::dvec3 &p) const noexcept { return length(p); }
+
+       /// get ground tile
+       Tile &TileAt(const glm::dvec3 &) noexcept;
+       const Tile &TileAt(const glm::dvec3 &) const noexcept;
+       const TileType &TileTypeAt(const glm::dvec3 &) const noexcept;
+
        /// Get the tile at given surface and coordinates.
-       Tile &TileAt(int surface, int x, int y) {
-               return tiles[IndexOf(surface, x, y)];
-       }
-       const Tile &TileAt(int surface, int x, int y) const {
-               return tiles[IndexOf(surface, x, y)];
-       }
+       Tile &TileAt(int surface, int x, int y) noexcept;
+       const Tile &TileAt(int surface, int x, int y) const noexcept;
+       const TileType &TypeAt(int surface, int x, int y) const noexcept;
 
-       const TileType &TypeAt(int surface, int x, int y) const;
+       /// The length in tiles of the side of each surface.
+       int SideLength() const { return sidelength; }
+
+       // center point of tile on surface at elevation
+       glm::dvec3 TileCenter(int surface, int x, int y, double elevation = 0.0) const noexcept;
 
+       void BuildVAO(const Set<TileType> &);
+       void Draw(app::Assets &, graphics::Viewport &) override;
+
+private:
        /// Convert coordinates into a tile index.
        int IndexOf(int surface, int x, int y) const {
                assert(0 <= surface && surface <= 5);
@@ -52,10 +69,6 @@ public:
                assert(0 <= y && y < sidelength);
                return surface * TilesPerSurface() + y * SideLength() + x;
        }
-       /// The length of the side of each surface.
-       int SideLength() const {
-               return sidelength;
-       }
        /// The number of tiles of one surface.
        int TilesPerSurface() const {
                return SideLength() * SideLength();
@@ -65,38 +78,13 @@ public:
                return 6 * TilesPerSurface();
        }
 
-       double TileToPosition(int t) const noexcept { return double(t) - Radius(); }
-       int PositionToTile(double p) const noexcept { return int(p + Radius()); }
-
-       // tile coordinates of position on surface
-       glm::ivec2 SurfacePosition(int surface, const glm::dvec3 &) const noexcept;
-       // height of point over surface
-       double SurfaceElevation(int surface, const glm::dvec3 &) const noexcept;
-       // center point of tile on surface at elevation
-       glm::dvec3 TileCenter(int surface, int x, int y, double elevation = 0.0) const noexcept;
-
-       static glm::dvec3 SurfaceNormal(int srf) noexcept {
-               glm::dvec3 nrm(0.0);
-               nrm[(srf + 2) % 3] = srf < 3 ? 1.0 : -1.0;
-               return nrm;
-       }
-       static glm::dmat3 SurfaceOrientation(int srf) noexcept {
-               glm::dmat3 mat(0.0);
-               mat[(srf + 0) % 3][0] = 1.0;
-               mat[(srf + 2) % 3][1] = srf < 3 ? -1.0 : 1.0;
-               mat[(srf + 1) % 3][2] = srf < 3 ? 1.0 : -1.0;
-               return mat;
-       }
-
-       void BuildVAO(const Set<TileType> &);
-       void Draw(app::Assets &, graphics::Viewport &) override;
-
 private:
        int sidelength;
        std::vector<Tile> tiles;
 
        struct Attributes {
                glm::vec3 position;
+               glm::vec3 normal;
                glm::vec3 tex_coord;
        };
        std::unique_ptr<graphics::SimpleVAO<Attributes, unsigned int>> vao;
index b80be094129011d029098b23b5986753e61d5f2d..49380ac8afdbee816cc6fc6658b2e2b6f78161f4 100644 (file)
@@ -355,28 +355,107 @@ Planet::Planet(int sidelength)
 Planet::~Planet() {
 }
 
-const TileType &Planet::TypeAt(int srf, int x, int y) const {
-       return GetSimulation().TileTypes()[TileAt(srf, x, y).type];
+namespace {
+/// map p onto cube, s gives the surface, u and v the position in [-1,1]
+void cubemap(const glm::dvec3 &p, int &s, double &u, double &v) noexcept {
+       const glm::dvec3 p_abs(abs(p));
+       const glm::bvec3 p_pos(greaterThan(p, glm::dvec3(0.0)));
+       double max_axis = 0.0;
+
+       if (p_pos.x && p_abs.x >= p_abs.y && p_abs.x >= p_abs.z) {
+               max_axis = p_abs.x;
+               u = p.y;
+               v = p.z;
+               s = 1;
+       }
+       if (!p_pos.x && p_abs.x >= p_abs.y && p_abs.x >= p_abs.z) {
+               max_axis = p_abs.x;
+               u = -p.y;
+               v = -p.z;
+               s = 4;
+       }
+       if (p_pos.y && p_abs.y >= p_abs.x && p_abs.y >= p_abs.z) {
+               max_axis = p_abs.y;
+               u = p.z;
+               v = p.x;
+               s = 2;
+       }
+       if (!p_pos.y && p_abs.y >= p_abs.x && p_abs.y >= p_abs.z) {
+               max_axis = p_abs.y;
+               u = -p.z;
+               v = -p.x;
+               s = 5;
+       }
+       if (p_pos.z && p_abs.z >= p_abs.x && p_abs.z >= p_abs.y) {
+               max_axis = p_abs.z;
+               u = p.x;
+               v = p.y;
+               s = 0;
+       }
+       if (!p_pos.z && p_abs.z >= p_abs.x && p_abs.z >= p_abs.y) {
+               max_axis = p_abs.z;
+               u = -p.x;
+               v = -p.y;
+               s = 3;
+       }
+       u /= max_axis;
+       v /= max_axis;
+}
+/// get p from cube, s being surface, u and v the position in [-1,1],
+/// gives a vector from the center to the surface
+glm::dvec3 cubeunmap(int s, double u, double v) {
+       switch (s) {
+               default:
+               case 0: return glm::dvec3(u, v, 1.0); // +Z
+               case 1: return glm::dvec3(1.0, u, v); // +X
+               case 2: return glm::dvec3(v, 1.0, u); // +Y
+               case 3: return glm::dvec3(-u, -v, -1.0); // -Z
+               case 4: return glm::dvec3(-1.0, -u, -v); // -X
+               case 5: return glm::dvec3(-v, -1.0, -u); // -Y
+       };
+}
 }
 
-glm::ivec2 Planet::SurfacePosition(int srf, const glm::dvec3 &pos) const noexcept {
-       return glm::ivec2(
-               PositionToTile(pos[(srf + 0) % 3]),
-               PositionToTile(pos[(srf + 1) % 3]));
+Tile &Planet::TileAt(const glm::dvec3 &p) noexcept {
+       int srf = 0;
+       double u = 0.0;
+       double v = 0.0;
+       cubemap(p, srf, u, v);
+       int x = glm::clamp(int(u * Radius() + Radius()), 0, sidelength - 1);
+       int y = glm::clamp(int(v * Radius() + Radius()), 0, sidelength - 1);
+       return TileAt(srf, x, y);
 }
 
-double Planet::SurfaceElevation(int srf, const glm::dvec3 &pos) const noexcept {
-       return srf < 3
-               ? pos[(srf + 2) % 3] - Radius()
-               : -pos[(srf + 2) % 3] - Radius();
+const Tile &Planet::TileAt(const glm::dvec3 &p) const noexcept {
+       int srf = 0;
+       double u = 0.0;
+       double v = 0.0;
+       cubemap(p, srf, u, v);
+       int x = glm::clamp(int(u * Radius() + Radius()), 0, sidelength - 1);
+       int y = glm::clamp(int(v * Radius() + Radius()), 0, sidelength - 1);
+       return TileAt(srf, x, y);
+}
+
+const TileType &Planet::TileTypeAt(const glm::dvec3 &p) const noexcept {
+       return GetSimulation().TileTypes()[TileAt(p).type];
+}
+
+Tile &Planet::TileAt(int surface, int x, int y) noexcept {
+       return tiles[IndexOf(surface, x, y)];
+}
+
+const Tile &Planet::TileAt(int surface, int x, int y) const noexcept {
+       return tiles[IndexOf(surface, x, y)];
+}
+
+const TileType &Planet::TypeAt(int srf, int x, int y) const noexcept {
+       return GetSimulation().TileTypes()[TileAt(srf, x, y).type];
 }
 
 glm::dvec3 Planet::TileCenter(int srf, int x, int y, double e) const noexcept {
-       glm::dvec3 center(0.0f);
-       center[(srf + 0) % 3] = x + 0.5 - Radius();
-       center[(srf + 1) % 3] = y + 0.5 - Radius();
-       center[(srf + 2) % 3] = srf < 3 ? (Radius() + e) : -(Radius() + e);
-       return center;
+       double u = (double(x) - Radius() + 0.5) / Radius();
+       double v = (double(y) - Radius() + 0.5) / Radius();
+       return normalize(cubeunmap(srf, u, v)) * (Radius() + e);
 }
 
 void Planet::BuildVAO(const Set<TileType> &ts) {
@@ -385,8 +464,10 @@ void Planet::BuildVAO(const Set<TileType> &ts) {
        vao->BindAttributes();
        vao->EnableAttribute(0);
        vao->EnableAttribute(1);
+       vao->EnableAttribute(2);
        vao->AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
-       vao->AttributePointer<glm::vec3>(1, false, offsetof(Attributes, tex_coord));
+       vao->AttributePointer<glm::vec3>(1, false, offsetof(Attributes, normal));
+       vao->AttributePointer<glm::vec3>(2, false, offsetof(Attributes, tex_coord));
        vao->ReserveAttributes(TilesTotal() * 4, GL_STATIC_DRAW);
        {
                auto attrib = vao->MapAttributes(GL_WRITE_ONLY);
@@ -398,33 +479,44 @@ void Planet::BuildVAO(const Set<TileType> &ts) {
                for (int index = 0, surface = 0; surface < 6; ++surface) {
                        for (int y = 0; y < sidelength; ++y) {
                                for (int x = 0; x < sidelength; ++x, ++index) {
+                                       glm::vec3 pos[5];
+                                       pos[0][(surface + 0) % 3] = x + 0 - offset;
+                                       pos[0][(surface + 1) % 3] = y + 0 - offset;
+                                       pos[0][(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       pos[1][(surface + 0) % 3] = x + 0 - offset;
+                                       pos[1][(surface + 1) % 3] = y + 1 - offset;
+                                       pos[1][(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       pos[2][(surface + 0) % 3] = x + 1 - offset;
+                                       pos[2][(surface + 1) % 3] = y + 0 - offset;
+                                       pos[2][(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       pos[3][(surface + 0) % 3] = x + 1 - offset;
+                                       pos[3][(surface + 1) % 3] = y + 1 - offset;
+                                       pos[3][(surface + 2) % 3] = surface < 3 ? offset : -offset;
+
                                        float tex = ts[TileAt(surface, x, y).type].texture;
                                        const float tex_v_begin = surface < 3 ? 1.0f : 0.0f;
                                        const float tex_v_end = surface < 3 ? 0.0f : 1.0f;
-                                       attrib[4 * index + 0].position[(surface + 0) % 3] = x + 0 - offset;
-                                       attrib[4 * index + 0].position[(surface + 1) % 3] = y + 0 - offset;
-                                       attrib[4 * index + 0].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+
+                                       attrib[4 * index + 0].position = normalize(pos[0]) * offset;
+                                       attrib[4 * index + 0].normal = pos[0];
                                        attrib[4 * index + 0].tex_coord[0] = 0.0f;
                                        attrib[4 * index + 0].tex_coord[1] = tex_v_begin;
                                        attrib[4 * index + 0].tex_coord[2] = tex;
 
-                                       attrib[4 * index + 1].position[(surface + 0) % 3] = x + 0 - offset;
-                                       attrib[4 * index + 1].position[(surface + 1) % 3] = y + 1 - offset;
-                                       attrib[4 * index + 1].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       attrib[4 * index + 1].position = normalize(pos[1]) * offset;
+                                       attrib[4 * index + 1].normal = pos[1];
                                        attrib[4 * index + 1].tex_coord[0] = 0.0f;
                                        attrib[4 * index + 1].tex_coord[1] = tex_v_end;
                                        attrib[4 * index + 1].tex_coord[2] = tex;
 
-                                       attrib[4 * index + 2].position[(surface + 0) % 3] = x + 1 - offset;
-                                       attrib[4 * index + 2].position[(surface + 1) % 3] = y + 0 - offset;
-                                       attrib[4 * index + 2].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       attrib[4 * index + 2].position = normalize(pos[2]) * offset;
+                                       attrib[4 * index + 2].normal = pos[2];
                                        attrib[4 * index + 2].tex_coord[0] = 1.0f;
                                        attrib[4 * index + 2].tex_coord[1] = tex_v_begin;
                                        attrib[4 * index + 2].tex_coord[2] = tex;
 
-                                       attrib[4 * index + 3].position[(surface + 0) % 3] = x + 1 - offset;
-                                       attrib[4 * index + 3].position[(surface + 1) % 3] = y + 1 - offset;
-                                       attrib[4 * index + 3].position[(surface + 2) % 3] = surface < 3 ? offset : -offset;
+                                       attrib[4 * index + 3].position = normalize(pos[3]) * offset;
+                                       attrib[4 * index + 3].normal = pos[3];
                                        attrib[4 * index + 3].tex_coord[0] = 1.0f;
                                        attrib[4 * index + 3].tex_coord[1] = tex_v_end;
                                        attrib[4 * index + 3].tex_coord[2] = tex;
@@ -469,19 +561,7 @@ void Planet::Draw(app::Assets &assets, graphics::Viewport &viewport) {
        if (!vao) return;
 
        vao->Bind();
-       const glm::mat4 &MV = assets.shaders.planet_surface.MV();
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 0);
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 1);
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 2);
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 3);
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 4);
-       assets.shaders.planet_surface.SetNormal(glm::vec3(MV * glm::vec4(0.0f, -1.0f, 0.0f, 0.0f)));
-       vao->DrawTriangles(TilesPerSurface() * 6, TilesPerSurface() * 6 * 5);
+       vao->DrawTriangles(TilesTotal() * 6);
 }
 
 
index 1ab0bf4373ab4d7c5708042acca8fae1756ed29e..3431801b3c1ea0a877c7e2ac8b586edb65704330 100644 (file)
@@ -31,47 +31,6 @@ void PlanetTest::testPositionConversion() {
        CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
                "wrong radius of planet",
                2.5, p.Radius(), std::numeric_limits<double>::epsilon());
-
-       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               -2.5, p.TileToPosition(0), std::numeric_limits<double>::epsilon());
-       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               -0.5, p.TileToPosition(2), std::numeric_limits<double>::epsilon());
-       CPPUNIT_ASSERT_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               2, p.PositionToTile(0.1));
-       CPPUNIT_ASSERT_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               2, p.PositionToTile(-0.1));
-       CPPUNIT_ASSERT_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               1, p.PositionToTile(-0.6));
-       CPPUNIT_ASSERT_EQUAL_MESSAGE(
-               "wrong scalar conversion",
-               4, p.PositionToTile(2.0));
-
-       AssertEqual(
-               "wrong surface position",
-               glm::ivec2(2, 2), p.SurfacePosition(0, glm::dvec3(0.0, 0.0, 2.5))
-       );
-       AssertEqual(
-               "wrong surface position",
-               glm::ivec2(2, 2), p.SurfacePosition(0, glm::dvec3(0.1, 0.1, 2.5))
-       );
-       AssertEqual(
-               "wrong surface position",
-               glm::ivec2(2, 2), p.SurfacePosition(0, glm::dvec3(-0.1, -0.1, 2.5))
-       );
-       AssertEqual(
-               "wrong surface position",
-               glm::ivec2(3, 1), p.SurfacePosition(0, glm::dvec3(1.0, -1.0, 2.5))
-       );
-
-       AssertEqual(
-               "wrong tile center",
-               glm::dvec3(0.0, 0.0, 2.5), p.TileCenter(0, 2, 2)
-       );
 }
 
 }