diff options
-rw-r--r-- | application/main.cpp | 7 | ||||
-rw-r--r-- | game/network/rail.cpp | 68 | ||||
-rw-r--r-- | game/network/rail.h | 9 | ||||
-rw-r--r-- | iwyu.json | 16 | ||||
-rw-r--r-- | utility/stream_support.hpp | 12 |
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>>; @@ -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 |