summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--application/main.cpp7
-rw-r--r--game/network/rail.cpp68
-rw-r--r--game/network/rail.h9
-rw-r--r--iwyu.json16
-rw-r--r--utility/stream_support.hpp12
5 files changed, 106 insertions, 6 deletions
diff --git a/application/main.cpp b/application/main.cpp
index 2b62953..a723b20 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -14,7 +14,6 @@
#include <gfx/manualCameraController.h>
#include <gfx/renderable.h>
#include <gfx/window.h>
-#include <glm/glm.hpp>
#include <memory>
#include <special_members.hpp>
#include <utility>
@@ -69,9 +68,9 @@ public:
world.create<Terrain>();
auto rl = world.create<RailLinks>();
auto a = rl->addLink<RailLinkStraight>({-1190, 5, -1190}, {-1190, 6, -1180});
- auto b = rl->addLink<RailLinkStraight>(a->ends.back().first->pos, glm::vec3 {-1180, 5, -1180});
- auto c = rl->addLink<RailLinkStraight>(b->ends.back().first->pos, glm::vec3 {-1180, 4, -1190});
- rl->addLink<RailLinkStraight>(c->ends.back().first->pos, a->ends.front().first->pos);
+ auto b = rl->addLink<RailLinkCurve>(a->ends.back().first->pos, {-1180, 5, -1180}, {-1185, -1180});
+ auto c = rl->addLink<RailLinkStraight>(b->ends.back().first->pos, {-1180, 4, -1190});
+ rl->addLink<RailLinkCurve>(c->ends.back().first->pos, a->ends.front().first->pos, {-1185, -1190});
Shader shader;
Camera camera({-1250.0F, 35.0F, -1250.0F}, 70.0F, (float)DISPLAY_WIDTH / (float)DISPLAY_HEIGHT, 0.1F, 10000.0F);
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index ecec0c0..2ae65f7 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -7,8 +7,10 @@
#include <gfx/gl/shader.h>
#include <gfx/models/texture.h>
#include <gfx/models/vertex.hpp>
+#include <glm/gtc/constants.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/transform.hpp>
+#include <glm/gtx/vector_angle.hpp>
#include <numbers>
#include <utility>
@@ -35,7 +37,19 @@ RailLinks::addLink(glm::vec3 a, glm::vec3 b)
return links.create<T>(Link::End {node1, true}, Link::End {node2, true});
}
+template<RailLinkConcept T>
+std::shared_ptr<T>
+RailLinks::addLink(glm::vec3 a, glm::vec3 b, glm::vec2 centre)
+{
+ 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}, centre);
+}
+
template std::shared_ptr<RailLinkStraight> RailLinks::addLink(glm::vec3, glm::vec3);
+template std::shared_ptr<RailLinkCurve> RailLinks::addLink(glm::vec3, glm::vec3, glm::vec2);
+
void
RailLink::render(const Shader &) const
{
@@ -54,6 +68,8 @@ constexpr const std::array<std::pair<glm::vec3, float>, 4> railCrossSection {{
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)};
+constexpr auto half_pi {glm::half_pi<float>()};
+constexpr auto sleepers {5.F}; // There are 5 repetitions of sleepers in the texture
template<typename V>
auto
@@ -65,12 +81,26 @@ flat_orientation(const V & diff)
return (std::isnan(e[0][0])) ? oneeighty : e;
}
+template<typename T>
+constexpr auto
+round_frac(const T & v, const T & frac)
+{
+ return std::round(v / frac) * frac;
+}
+
+template<typename T>
+constexpr auto
+round_sleepers(const T & v)
+{
+ return std::round(v / sleepers) * sleepers;
+}
+
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 len = round_sleepers(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};
@@ -85,3 +115,39 @@ RailLinkStraight::RailLinkStraight(End a, End b) : RailLink(std::move(a), std::m
}
meshes.create<Mesh>(vertices, indices, GL_TRIANGLE_STRIP);
}
+
+RailLinkCurve::RailLinkCurve(End a, End b, glm::vec2 c) : RailLink(std::move(a), std::move(b)), centre(c)
+{
+ const auto & e0p {ends[0].first->pos};
+ const auto & e1p {ends[1].first->pos};
+ const glm::vec3 centre3 {centre.x, e0p.y, centre.y};
+ const auto diffa = centre3 - e0p;
+ const auto diffb = centre3 - e1p;
+ const auto anga = glm::orientedAngle(glm::normalize(diffa), north, up) - half_pi;
+ const auto angb = [&diffb, &anga]() {
+ const auto angb = glm::orientedAngle(glm::normalize(diffb), north, up) - half_pi;
+ return (angb < anga) ? angb + glm::radians(360.f) : angb;
+ }();
+ const auto radius = glm::length(e0p - centre3);
+ const auto length = round_sleepers(radius * (angb - anga) / 2.F);
+ const auto step {glm::vec3 {std::abs(angb - anga), e1p.y - e0p.y, length} / std::round(angb - anga) / 5.F};
+ const auto trans {glm::translate(centre3)};
+
+ auto addRcs = [this, trans, radius](auto arc) {
+ const auto t {trans * glm::rotate(arc.x, up) * glm::translate(glm::vec3 {radius, arc.y, 0.F})};
+ for (const auto & rcs : railCrossSection) {
+ const glm::vec3 m {(t * glm::vec4 {rcs.first, 1})};
+ vertices.emplace_back(m, glm::vec2 {rcs.second, arc.z}, up);
+ }
+ };
+ for (glm::vec3 arc = {anga, 0.F, 0.F}; arc.x < angb; arc += step) {
+ addRcs(arc);
+ }
+ addRcs(glm::vec3 {angb, e1p.y - e0p.y, length});
+
+ for (auto n = 4U; n < vertices.size(); n += 1) {
+ indices.push_back(n);
+ indices.push_back(n - 4);
+ }
+ meshes.create<Mesh>(vertices, indices, GL_TRIANGLE_STRIP);
+}
diff --git a/game/network/rail.h b/game/network/rail.h
index ef119bc..7e1f5ac 100644
--- a/game/network/rail.h
+++ b/game/network/rail.h
@@ -33,12 +33,21 @@ public:
RailLinkStraight(End, End);
};
+class RailLinkCurve : public RailLink {
+public:
+ RailLinkCurve(End, End, glm::vec2);
+
+private:
+ glm::vec2 centre;
+};
+
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);
+ template<RailLinkConcept T> std::shared_ptr<T> addLink(glm::vec3, glm::vec3, glm::vec2);
private:
using Nodes = std::set<NodePtr, PtrSorter<NodePtr>>;
diff --git a/iwyu.json b/iwyu.json
index 0df2666..763fb95 100644
--- a/iwyu.json
+++ b/iwyu.json
@@ -33,6 +33,22 @@
},
{
"include": [
+ "@<glm/gtc/constants.inl>",
+ "private",
+ "<glm/gtc/constants.hpp>",
+ "public"
+ ]
+ },
+ {
+ "include": [
+ "@<glm/gtx/vector_angle.inl>",
+ "private",
+ "<glm/gtx/vector_angle.hpp>",
+ "public"
+ ]
+ },
+ {
+ "include": [
"@<glm/gtx/rotate_vector.inl>",
"private",
"<glm/gtx/rotate_vector.hpp>",
diff --git a/utility/stream_support.hpp b/utility/stream_support.hpp
index 6ab1bd1..9561e58 100644
--- a/utility/stream_support.hpp
+++ b/utility/stream_support.hpp
@@ -5,7 +5,7 @@
template<glm::length_t L, glm::length_t R, typename T, glm::qualifier Q>
std::ostream &
-operator<<(std::ostream & s, glm::mat<L, R, T, Q> & m)
+operator<<(std::ostream & s, const glm::mat<L, R, T, Q> & m)
{
for (int y = 0; y < m.length(); y++) {
const auto & col = m[y];
@@ -17,4 +17,14 @@ operator<<(std::ostream & s, glm::mat<L, R, T, Q> & m)
return s;
}
+template<glm::length_t L, typename T, glm::qualifier Q>
+std::ostream &
+operator<<(std::ostream & s, const glm::vec<L, T, Q> & v)
+{
+ for (int x = 0; x < L; x++) {
+ s << v[x] << ", ";
+ }
+ return s;
+}
+
#endif