summaryrefslogtreecommitdiff
path: root/game/network
diff options
context:
space:
mode:
Diffstat (limited to 'game/network')
-rw-r--r--game/network/link.cpp18
-rw-r--r--game/network/link.h51
-rw-r--r--game/network/rail.cpp87
-rw-r--r--game/network/rail.h52
4 files changed, 208 insertions, 0 deletions
diff --git a/game/network/link.cpp b/game/network/link.cpp
new file mode 100644
index 0000000..65aefd6
--- /dev/null
+++ b/game/network/link.cpp
@@ -0,0 +1,18 @@
+#include "link.h"
+#include <compare>
+#include <tuple>
+
+Link::Link(End a, End b) : ends {{std::move(a), std::move(b)}} { }
+
+bool
+operator<(const glm::vec3 & a, const glm::vec3 & b)
+{
+ // NOLINTNEXTLINE(hicpp-use-nullptr,modernize-use-nullptr)
+ return std::tie(a.x, a.z, a.y) < std::tie(b.x, b.z, b.y);
+}
+
+bool
+operator<(const Node & a, const Node & b)
+{
+ return a.pos < b.pos;
+}
diff --git a/game/network/link.h b/game/network/link.h
new file mode 100644
index 0000000..0da413c
--- /dev/null
+++ b/game/network/link.h
@@ -0,0 +1,51 @@
+#ifndef LINK_H
+#define LINK_H
+
+#include <array>
+#include <glm/glm.hpp>
+#include <memory>
+#include <special_members.hpp>
+#include <utility>
+
+// Generic network node
+// something that can be travelled to
+// it has location
+class Node {
+public:
+ explicit Node(glm::vec3 p) noexcept : pos(p) {};
+ virtual ~Node() noexcept = default;
+ NO_COPY(Node);
+ NO_MOVE(Node);
+
+ glm::vec3 pos;
+};
+using NodePtr = std::shared_ptr<Node>;
+
+// Generic network link
+// something that can be travelled along
+// it joins 2 nodes
+class Link {
+public:
+ // side determines which edges can be moved to next, must alternate
+ using End = std::pair<NodePtr, bool /*side*/>;
+
+ Link(End, End);
+ virtual ~Link() = default;
+ NO_COPY(Link);
+ NO_MOVE(Link);
+
+ std::array<End, 2> ends;
+};
+
+template<typename T> struct PtrSorter {
+ bool
+ operator()(const T & a, const T & b) const
+ {
+ return *a < *b;
+ }
+};
+
+bool operator<(const glm::vec3 & a, const glm::vec3 & b);
+bool operator<(const Node & a, const Node & b);
+
+#endif
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
new file mode 100644
index 0000000..ecec0c0
--- /dev/null
+++ b/game/network/rail.cpp
@@ -0,0 +1,87 @@
+#include "rail.h"
+#include "game/network/link.h"
+#include <GL/glew.h>
+#include <array>
+#include <cache.h>
+#include <cmath>
+#include <gfx/gl/shader.h>
+#include <gfx/models/texture.h>
+#include <gfx/models/vertex.hpp>
+#include <glm/gtx/rotate_vector.hpp>
+#include <glm/gtx/transform.hpp>
+#include <numbers>
+#include <utility>
+
+RailLinks::RailLinks() : texture {Texture::cachedTexture.get("rails.jpg")} { }
+void RailLinks::tick(TickDuration) { }
+
+static const auto identityModel {glm::identity<glm::mat4>()};
+
+void
+RailLinks::render(const Shader & shader) const
+{
+ shader.setModel(identityModel);
+ texture->Bind();
+ links.apply(&RailLink::render, shader);
+}
+
+template<RailLinkConcept T>
+std::shared_ptr<T>
+RailLinks::addLink(glm::vec3 a, glm::vec3 b)
+{
+ const auto node1 = *nodes.insert(std::make_shared<Node>(a)).first;
+ const auto node2 = *nodes.insert(std::make_shared<Node>(b)).first;
+ // TODO set end flag properly
+ return links.create<T>(Link::End {node1, true}, Link::End {node2, true});
+}
+
+template std::shared_ptr<RailLinkStraight> RailLinks::addLink(glm::vec3, glm::vec3);
+void
+RailLink::render(const Shader &) const
+{
+ meshes.apply(&Mesh::Draw);
+}
+
+constexpr const std::array<std::pair<glm::vec3, float>, 4> railCrossSection {{
+ // ___________
+ // _/ \_
+ // left to right
+ {{-1.F, 0.F, 0.F}, 0.F},
+ {{-.75F, .25F, 0.F}, 0.125F},
+ {{.75F, .25F, 0.F}, 0.875F},
+ {{1.F, 0.F, 0.F}, 1.F},
+}};
+constexpr const glm::vec3 up {0, 1, 0};
+constexpr const glm::vec3 north {0, 0, 1};
+const auto oneeighty {glm::rotate(std::numbers::pi_v<float>, up)};
+
+template<typename V>
+auto
+flat_orientation(const V & diff)
+{
+ const auto flatdiff {glm::normalize(glm::vec3 {diff.x, 0, diff.z})};
+ auto e {glm::orientation(flatdiff, north)};
+ // Handle if diff is exactly opposite to north
+ return (std::isnan(e[0][0])) ? oneeighty : e;
+}
+
+RailLinkStraight::RailLinkStraight(End a, End b) : RailLink(std::move(a), std::move(b))
+{
+ vertices.reserve(2 * railCrossSection.size());
+ indices.reserve(2 * railCrossSection.size());
+ const auto diff {ends[1].first->pos - ends[0].first->pos};
+ const auto len = glm::length(diff) / 2.F;
+ const auto e {flat_orientation(diff)};
+ for (int ei = 0; ei < 2; ei++) {
+ const auto trans {glm::translate(ends[ei].first->pos) * e};
+ for (const auto & rcs : railCrossSection) {
+ const glm::vec3 m {(trans * glm::vec4 {rcs.first, 1})};
+ vertices.emplace_back(m, glm::vec2 {rcs.second, ei ? len : 0.F}, up);
+ if (vertices.size() > railCrossSection.size()) {
+ indices.push_back(vertices.size() - railCrossSection.size() - 1);
+ indices.push_back(vertices.size() - 1);
+ }
+ }
+ }
+ meshes.create<Mesh>(vertices, indices, GL_TRIANGLE_STRIP);
+}
diff --git a/game/network/rail.h b/game/network/rail.h
new file mode 100644
index 0000000..ef119bc
--- /dev/null
+++ b/game/network/rail.h
@@ -0,0 +1,52 @@
+#ifndef RAILLINKS_H
+#define RAILLINKS_H
+
+#include "collection.hpp"
+#include "game/worldobject.h"
+#include "gfx/models/mesh.h"
+#include "gfx/models/vertex.hpp"
+#include "gfx/renderable.h"
+#include "link.h"
+#include <glm/glm.hpp>
+#include <memory>
+#include <set>
+#include <vector>
+class Shader;
+class Texture;
+
+// A piece of rail track
+class RailLink : public Link, public Renderable {
+public:
+ using Link::Link;
+
+ void render(const Shader &) const override;
+
+protected:
+ RailLink();
+ Collection<Mesh, false> meshes;
+ std::vector<Vertex> vertices;
+ std::vector<unsigned int> indices;
+};
+
+class RailLinkStraight : public RailLink {
+public:
+ RailLinkStraight(End, End);
+};
+
+template<typename T> concept RailLinkConcept = std::is_base_of_v<RailLink, T>;
+
+class RailLinks : public Renderable, public WorldObject {
+public:
+ RailLinks();
+ template<RailLinkConcept T> std::shared_ptr<T> addLink(glm::vec3, glm::vec3);
+
+private:
+ using Nodes = std::set<NodePtr, PtrSorter<NodePtr>>;
+ Collection<RailLink> links;
+ Nodes nodes;
+ void render(const Shader &) const override;
+ void tick(TickDuration elapsed) override;
+ std::shared_ptr<Texture> texture;
+};
+
+#endif