summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2021-02-07 11:32:15 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2021-02-07 11:32:15 +0000
commit30e3c9625856c24fa88ec148da6865657414c77d (patch)
tree76050748b6816606254117b02d3a681edeb77666
parentFix up the maths in creating curved rails (diff)
downloadilt-30e3c9625856c24fa88ec148da6865657414c77d.tar.bz2
ilt-30e3c9625856c24fa88ec148da6865657414c77d.tar.xz
ilt-30e3c9625856c24fa88ec148da6865657414c77d.zip
Links have length, ends have entry direction
-rw-r--r--application/main.cpp8
-rw-r--r--game/network/link.cpp2
-rw-r--r--game/network/link.h6
-rw-r--r--game/network/rail.cpp100
-rw-r--r--game/network/rail.h23
5 files changed, 84 insertions, 55 deletions
diff --git a/application/main.cpp b/application/main.cpp
index 73d4440..38874f4 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -69,16 +69,16 @@ public:
{
const glm::vec3 j {-1100, 5, -1100}, k {-1100, 5, -1000}, l {-1150, 10, -1050}, m {-1050, 10, -1050};
rl->addLink<RailLinkStraight>(j, k);
- rl->addLink<RailLinkCurve>(k, l, {l.x, k.z});
+ rl->addLink<RailLinkCurve>(k, l, glm::vec2 {l.x, k.z});
rl->addLink<RailLinkStraight>(l, m);
- rl->addLink<RailLinkCurve>(j, m, {m.x, j.z});
+ rl->addLink<RailLinkCurve>(j, m, glm::vec2 {m.x, j.z});
}
{
const glm::vec3 j {-1190, 5, -1190}, k {-1190, 6, -1180}, l {-1180, 4, -1180}, m {-1180, 4, -1190};
rl->addLink<RailLinkStraight>(j, k);
- rl->addLink<RailLinkCurve>(l, k, {-1185, k.z});
+ rl->addLink<RailLinkCurve>(l, k, glm::vec2 {-1185, k.z});
rl->addLink<RailLinkStraight>(l, m);
- rl->addLink<RailLinkCurve>(j, m, {-1185, m.z});
+ rl->addLink<RailLinkCurve>(j, m, glm::vec2 {-1185, m.z});
}
Shader shader;
diff --git a/game/network/link.cpp b/game/network/link.cpp
index 65aefd6..ad09341 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -2,7 +2,7 @@
#include <compare>
#include <tuple>
-Link::Link(End a, End b) : ends {{std::move(a), std::move(b)}} { }
+Link::Link(End a, End b, float l) : ends {{std::move(a), std::move(b)}}, length {l} { }
bool
operator<(const glm::vec3 & a, const glm::vec3 & b)
diff --git a/game/network/link.h b/game/network/link.h
index 0da413c..b22d0d0 100644
--- a/game/network/link.h
+++ b/game/network/link.h
@@ -26,15 +26,15 @@ using NodePtr = std::shared_ptr<Node>;
// 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*/>;
+ using End = std::pair<NodePtr, float /*dir*/>;
- Link(End, End);
+ Link(End, End, float);
virtual ~Link() = default;
NO_COPY(Link);
NO_MOVE(Link);
std::array<End, 2> ends;
+ float length;
};
template<typename T> struct PtrSorter {
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index 93fc9f6..0858b66 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -12,6 +12,7 @@
#include <glm/gtx/transform.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <numbers>
+#include <type_traits>
#include <utility>
RailLinks::RailLinks() : texture {Texture::cachedTexture.get("rails.jpg")} { }
@@ -27,29 +28,6 @@ RailLinks::render(const Shader & shader) const
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<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
{
@@ -69,6 +47,8 @@ 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 pi {glm::pi<float>()};
+constexpr auto two_pi {glm::two_pi<float>()};
constexpr auto sleepers {5.F}; // There are 5 repetitions of sleepers in the texture
template<typename V>
@@ -103,12 +83,14 @@ round_sleepers(const T & v)
return std::round(v / sleepers) * sleepers;
}
-RailLinkStraight::RailLinkStraight(End a, End b) : RailLink(std::move(a), std::move(b))
+RailLinkStraight::RailLinkStraight(const NodePtr & a, const NodePtr & b) : RailLinkStraight(a, b, b->pos - a->pos) { }
+
+RailLinkStraight::RailLinkStraight(NodePtr a, NodePtr b, const glm::vec3 & diff) :
+ RailLink({std::move(a), flat_angle(diff)}, {std::move(b), flat_angle(-diff)}, glm::length(diff))
{
vertices.reserve(2 * railCrossSection.size());
indices.reserve(2 * railCrossSection.size());
- const auto diff {ends[1].first->pos - ends[0].first->pos};
- const auto len = round_sleepers(glm::length(diff) / 2.F);
+ const auto len = round_sleepers(length / 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};
@@ -124,36 +106,72 @@ 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)
+constexpr inline glm::vec3
+operator!(const glm::vec2 & v)
+{
+ return {v.x, 0, v.y};
+}
+
+constexpr inline float
+arc_length(const Arc & arc)
+{
+ return arc.second - arc.first;
+}
+
+constexpr inline float
+normalize(float ang)
+{
+ while (ang > pi) {
+ ang -= two_pi;
+ }
+ while (ang <= -pi) {
+ ang += two_pi;
+ }
+ return ang;
+}
+
+inline Arc
+create_arc(const glm::vec3 centre3, glm::vec3 e0p, glm::vec3 e1p)
{
- 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 = flat_angle(diffa);
const auto angb = [&diffb, &anga]() {
const auto angb = flat_angle(diffb);
- return (angb < anga) ? angb + glm::two_pi<float>() : angb;
+ return (angb < anga) ? angb + two_pi : angb;
}();
- const auto radius = glm::length(e0p - centre3);
- const auto length = round_sleepers(radius * (angb - anga) / 2.F);
- const auto segs = std::round(5.F * length / std::pow(radius, 0.7F));
- const auto step {glm::vec3 {angb - anga, e1p.y - e0p.y, length} / segs};
- const auto trans {glm::translate(centre3)};
+ return {anga, angb};
+}
+
+RailLinkCurve::RailLinkCurve(const NodePtr & a, const NodePtr & b, glm::vec2 c) :
+ RailLinkCurve(a, b, {c.x, a->pos.y, c.y}, create_arc(!c, a->pos, b->pos))
+{
+}
+
+RailLinkCurve::RailLinkCurve(const NodePtr & a, const NodePtr & b, glm::vec3 c, const Arc arc) :
+ RailLink({a, normalize(arc.first - half_pi)}, {b, normalize(arc.second + half_pi)},
+ (glm::length(a->pos - c)) * arc_length(arc)),
+ centreBase(c)
+{
+ const auto & e0p {ends[0].first->pos};
+ const auto & e1p {ends[1].first->pos};
+ const auto radius = glm::length(e0p - centreBase);
+ const auto slength = round_sleepers(length / 2.F);
+ const auto segs = std::round(5.F * slength / std::pow(radius, 0.7F));
+ const auto step {glm::vec3 {arc_length(arc), e1p.y - e0p.y, slength} / segs};
+ const auto trans {glm::translate(centreBase)};
auto addRcs = [this, trans, radius](auto arc) {
- const auto t {trans * glm::rotate(glm::half_pi<float>() - arc.x, up)
- * glm::translate(glm::vec3 {radius, arc.y, 0.F})};
+ const auto t {trans * glm::rotate(half_pi - 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);
+ for (glm::vec3 swing = {arc.first, 0.F, 0.F}; swing.x < arc.second; swing += step) {
+ addRcs(swing);
}
- addRcs(glm::vec3 {angb, e1p.y - e0p.y, length});
+ addRcs(glm::vec3 {arc.second, e1p.y - e0p.y, slength});
for (auto n = 4U; n < vertices.size(); n += 1) {
indices.push_back(n - 4);
diff --git a/game/network/rail.h b/game/network/rail.h
index 7e1f5ac..3ab0c83 100644
--- a/game/network/rail.h
+++ b/game/network/rail.h
@@ -10,6 +10,7 @@
#include <glm/glm.hpp>
#include <memory>
#include <set>
+#include <utility>
#include <vector>
class Shader;
class Texture;
@@ -22,7 +23,6 @@ public:
void render(const Shader &) const override;
protected:
- RailLink();
Collection<Mesh, false> meshes;
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
@@ -30,15 +30,20 @@ protected:
class RailLinkStraight : public RailLink {
public:
- RailLinkStraight(End, End);
+ RailLinkStraight(const NodePtr &, const NodePtr &);
+
+private:
+ RailLinkStraight(NodePtr, NodePtr, const glm::vec3 & diff);
};
+using Arc = std::pair<float, float>;
class RailLinkCurve : public RailLink {
public:
- RailLinkCurve(End, End, glm::vec2);
+ RailLinkCurve(const NodePtr &, const NodePtr &, glm::vec2);
private:
- glm::vec2 centre;
+ RailLinkCurve(const NodePtr &, const NodePtr &, glm::vec3, const Arc);
+ glm::vec3 centreBase;
};
template<typename T> concept RailLinkConcept = std::is_base_of_v<RailLink, T>;
@@ -46,8 +51,14 @@ 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);
+ template<RailLinkConcept T, typename... Params>
+ std::shared_ptr<T>
+ addLink(glm::vec3 a, glm::vec3 b, Params &&... params)
+ {
+ const auto node1 = *nodes.insert(std::make_shared<Node>(a)).first;
+ const auto node2 = *nodes.insert(std::make_shared<Node>(b)).first;
+ return links.create<T>(node1, node2, std::forward<Params>(params)...);
+ }
private:
using Nodes = std::set<NodePtr, PtrSorter<NodePtr>>;