diff options
Diffstat (limited to 'game')
-rw-r--r-- | game/network/network.h | 19 | ||||
-rw-r--r-- | game/network/network.impl.h | 47 | ||||
-rw-r--r-- | game/network/rail.cpp | 154 | ||||
-rw-r--r-- | game/network/rail.h | 39 |
4 files changed, 133 insertions, 126 deletions
diff --git a/game/network/network.h b/game/network/network.h index fa311ac..5725360 100644 --- a/game/network/network.h +++ b/game/network/network.h @@ -1,5 +1,6 @@ #pragma once +#include "gfx/gl/instanceVertices.h" #include "link.h" #include <collection.h> #include <gfx/renderable.h> @@ -58,7 +59,17 @@ protected: std::shared_ptr<Texture> texture; }; -template<typename T> class NetworkOf : public Network, public Renderable { +template<typename LinkType> class NetworkLinkHolder { +public: + // Implemented per LinkType to configure vao + NetworkLinkHolder(); + friend LinkType; + glVertexArray vao; + mutable InstanceVertices<typename LinkType::Vertex> vertices; +}; + +template<typename T, typename... Links> +class NetworkOf : public Network, public Renderable, public NetworkLinkHolder<Links>... { protected: using Network::Network; @@ -75,7 +86,7 @@ public: requires std::is_base_of_v<T, L> { const auto node1 = candidateNodeAt(a).first, node2 = candidateNodeAt(b).first; - return std::make_shared<L>(node1, node2, std::forward<Params>(params)...); + return std::make_shared<L>(*this, node1, node2, std::forward<Params>(params)...); } template<typename L, typename... Params> @@ -84,7 +95,7 @@ public: requires std::is_base_of_v<T, L> { const auto node1 = nodeAt(a), node2 = nodeAt(b); - auto l {links.template create<L>(node1, node2, std::forward<Params>(params)...)}; + auto l {links.template create<L>(*this, node1, node2, std::forward<Params>(params)...)}; joinLinks(l); return l; } @@ -98,8 +109,6 @@ public: [[nodiscard]] float findNodeDirection(Node::AnyCPtr) const override; - void render(const SceneShader &) const override; - protected: Link::CCollection addJoins(); }; diff --git a/game/network/network.impl.h b/game/network/network.impl.h index f9595ed..ff29088 100644 --- a/game/network/network.impl.h +++ b/game/network/network.impl.h @@ -2,29 +2,18 @@ #include <gfx/gl/sceneShader.h> #include <gfx/models/texture.h> -template<typename T> +template<typename T, typename... Links> void -NetworkOf<T>::render(const SceneShader & shader) const -{ - if constexpr (std::is_base_of_v<Renderable, T>) { - shader.absolute.use(); - texture->bind(); - links.apply(&Renderable::render, shader); - } -} - -template<typename T> -void -NetworkOf<T>::joinLinks(const Link::Ptr & l) const +NetworkOf<T, Links...>::joinLinks(const Link::Ptr & l) const { for (const auto & ol : links.objects) { Network::joinLinks(l, ol); } } -template<typename T> +template<typename T, typename... Links> Link::Ptr -NetworkOf<T>::intersectRayLinks(const Ray<GlobalPosition3D> & ray) const +NetworkOf<T, Links...>::intersectRayLinks(const Ray<GlobalPosition3D> & ray) const { // Click link if (const auto link = std::find_if(links.objects.begin(), links.objects.end(), @@ -37,9 +26,9 @@ NetworkOf<T>::intersectRayLinks(const Ray<GlobalPosition3D> & ray) const return {}; } -template<typename T> +template<typename T, typename... Links> float -NetworkOf<T>::findNodeDirection(Node::AnyCPtr n) const +NetworkOf<T, Links...>::findNodeDirection(Node::AnyCPtr n) const { for (const auto & l : links.objects) { for (const auto & e : l->ends) { @@ -52,16 +41,16 @@ NetworkOf<T>::findNodeDirection(Node::AnyCPtr n) const throw std::runtime_error("Node exists but couldn't find it"); } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::candidateStraight(GlobalPosition3D n1, GlobalPosition3D n2) +NetworkOf<T, Links...>::candidateStraight(GlobalPosition3D n1, GlobalPosition3D n2) { return {candidateLink<typename T::StraightLink>(n1, n2)}; } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::candidateJoins(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::candidateJoins(GlobalPosition3D start, GlobalPosition3D end) { if (glm::length(RelativePosition3D(start - end)) < 2000.F) { return {}; @@ -73,24 +62,24 @@ NetworkOf<T>::candidateJoins(GlobalPosition3D start, GlobalPosition3D end) return {candidateLink<typename T::CurveLink>(c1s, c1e, c1c), candidateLink<typename T::CurveLink>(c2s, c2e, c2c)}; } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::candidateExtend(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::candidateExtend(GlobalPosition3D start, GlobalPosition3D end) { const auto [cstart, cend, centre] = genCurveDef(start, end, findNodeDirection(candidateNodeAt(start).first)); return {candidateLink<typename T::CurveLink>(cstart, cend, centre)}; } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::addStraight(GlobalPosition3D n1, GlobalPosition3D n2) +NetworkOf<T, Links...>::addStraight(GlobalPosition3D n1, GlobalPosition3D n2) { return {addLink<typename T::StraightLink>(n1, n2)}; } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::addJoins(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::addJoins(GlobalPosition3D start, GlobalPosition3D end) { if (glm::length(RelativePosition3D(start - end)) < 2000.F) { return {}; @@ -101,9 +90,9 @@ NetworkOf<T>::addJoins(GlobalPosition3D start, GlobalPosition3D end) return {addLink<typename T::CurveLink>(c1s, c1e, c1c), addLink<typename T::CurveLink>(c2s, c2e, c2c)}; } -template<typename T> +template<typename T, typename... Links> Link::CCollection -NetworkOf<T>::addExtend(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::addExtend(GlobalPosition3D start, GlobalPosition3D end) { const auto [cstart, cend, centre] = genCurveDef(start, end, findNodeDirection(nodeAt(start))); return {addLink<typename T::CurveLink>(cstart, cend, centre)}; diff --git a/game/network/rail.cpp b/game/network/rail.cpp index 79aaf97..176a704 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -1,24 +1,16 @@ #include "rail.h" #include "network.h" -#include <array> -#include <cmath> -#include <collection.h> -#include <cstddef> -#include <game/network/link.h> #include <game/network/network.impl.h> // IWYU pragma: keep -#include <gfx/models/vertex.h> -#include <glad/gl.h> -#include <glm/gtx/transform.hpp> -#include <maths.h> -#include <utility> -#include <vector> +#include <gfx/gl/sceneShader.h> +#include <gfx/gl/vertexArrayObject.h> +#include <gfx/models/texture.h> -template class NetworkOf<RailLink>; +template class NetworkOf<RailLink, RailLinkStraight, RailLinkCurve>; constexpr auto RAIL_CROSSSECTION_VERTICES {5U}; constexpr Size3D RAIL_HEIGHT {0, 0, 250.F}; -RailLinks::RailLinks() : NetworkOf<RailLink> {"rails.jpg"} { } +RailLinks::RailLinks() : NetworkOf<RailLink, RailLinkStraight, RailLinkCurve> {"rails.jpg"} { } void RailLinks::tick(TickDuration) @@ -81,34 +73,20 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) return addLink<RailLinkCurve>(start, end, centre.first); } -Mesh::Ptr -RailLink::defaultMesh(const std::span<Vertex> vertices) -{ - std::vector<unsigned int> indices; - for (auto n = RAIL_CROSSSECTION_VERTICES; n < vertices.size(); n += 1) { - indices.push_back(n - RAIL_CROSSSECTION_VERTICES); - indices.push_back(n); - } - - return std::make_unique<Mesh>(vertices, indices, GL_TRIANGLE_STRIP); -} - -void -RailLink::render(const SceneShader &) const -{ - mesh->Draw(); -} - -constexpr const std::array<std::pair<RelativePosition3D, float>, RAIL_CROSSSECTION_VERTICES> railCrossSection {{ - // ___________ - // _/ \_ - // left to right - {{-1900.F, 0.F, 0.F}, 0.F}, - {{-608.F, 0.F, RAIL_HEIGHT.z}, .34F}, - {{0, 0.F, RAIL_HEIGHT.z * .7F}, .5F}, - {{608.F, 0.F, RAIL_HEIGHT.z}, .66F}, - {{1900.F, 0.F, 0.F}, 1.F}, +constexpr const std::array<RelativePosition3D, RAIL_CROSSSECTION_VERTICES> railCrossSection {{ + {-1900.F, 0.F, 0.F}, + {-608.F, 0.F, RAIL_HEIGHT.z}, + {0, 0.F, RAIL_HEIGHT.z * .7F}, + {608.F, 0.F, RAIL_HEIGHT.z}, + {1900.F, 0.F, 0.F}, }}; +constexpr const std::array<float, RAIL_CROSSSECTION_VERTICES> railTexturePos { + 0.F, + .34F, + .5F, + .66F, + 1.F, +}; constexpr auto sleepers {5.F}; // There are 5 repetitions of sleepers in the texture inline auto @@ -117,58 +95,34 @@ round_sleepers(const float v) return round_frac(v, sleepers); } -RailLinkStraight::RailLinkStraight(const Node::Ptr & a, const Node::Ptr & b) : RailLinkStraight(a, b, b->pos - a->pos) +RailLinkStraight::RailLinkStraight( + NetworkLinkHolder<RailLinkStraight> & instances, const Node::Ptr & a, const Node::Ptr & b) : + RailLinkStraight(instances, a, b, b->pos - a->pos) { } -RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const RelativePosition3D & diff) : - Link({std::move(a), vector_yaw(diff)}, {std::move(b), vector_yaw(-diff)}, glm::length(diff)) +RailLinkStraight::RailLinkStraight( + NetworkLinkHolder<RailLinkStraight> & instances, Node::Ptr a, Node::Ptr b, const RelativePosition3D & diff) : + Link({std::move(a), vector_yaw(diff)}, {std::move(b), vector_yaw(-diff)}, glm::length(diff)), + instance {instances.vertices.acquire( + ends[0].node->pos, ends[1].node->pos, flat_orientation(diff), round_sleepers(length / 2000.F))} { - if (glGenVertexArrays) { - std::vector<Vertex> vertices; - vertices.reserve(2 * railCrossSection.size()); - const auto len = round_sleepers(length / 2000.F); - const glm::mat3 trans {flat_orientation(diff)}; - for (auto ei : {1U, 0U}) { - for (const auto & rcs : railCrossSection) { - const auto m {ends[ei].node->pos + GlobalPosition3D(trans * rcs.first)}; - vertices.emplace_back(m, TextureRelCoord {rcs.second, len * static_cast<float>(ei)}, up); - } - } - mesh = defaultMesh(vertices); - } } -RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, GlobalPosition2D c) : - RailLinkCurve(a, b, c || a->pos.z, {c || 0, a->pos, b->pos}) +RailLinkCurve::RailLinkCurve( + NetworkLinkHolder<RailLinkCurve> & instances, const Node::Ptr & a, const Node::Ptr & b, GlobalPosition2D c) : + RailLinkCurve(instances, a, b, c || a->pos.z, {c || 0, a->pos, b->pos}) { } -RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, GlobalPosition3D c, const Arc arc) : +RailLinkCurve::RailLinkCurve(NetworkLinkHolder<RailLinkCurve> & instances, const Node::Ptr & a, const Node::Ptr & b, + GlobalPosition3D c, const Arc arc) : Link({a, normalize(arc.first + half_pi)}, {b, normalize(arc.second - half_pi)}, glm::length(RelativePosition3D(a->pos - c)) * arc_length(arc)), - LinkCurve {c, glm::length(RelativePosition3D(ends[0].node->pos - c)), arc} + LinkCurve {c, glm::length(RelativePosition3D(ends[0].node->pos - c)), arc}, + instance {instances.vertices.acquire(ends[0].node->pos, ends[1].node->pos, c, round_sleepers(length / 2000.F), + half_pi - arc.first, half_pi - arc.second, radius)} { - if (glGenVertexArrays) { - const auto & e0p {ends[0].node->pos}; - const auto & e1p {ends[1].node->pos}; - const auto slength = round_sleepers(length / 2.F); - const auto segs = std::round(slength / std::pow(radius, 0.7F)); - const auto step {RelativePosition3D {arc_length(arc), e1p.z - e0p.z, slength / 1000.F} / segs}; - - auto segCount = static_cast<std::size_t>(std::lround(segs)) + 1; - std::vector<Vertex> vertices; - vertices.reserve(segCount * railCrossSection.size()); - for (RelativePosition3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) { - const auto t { - glm::rotate(half_pi - swing.x, up) * glm::translate(RelativePosition3D {radius, 0.F, swing.y})}; - for (const auto & rcs : railCrossSection) { - const auto m {centreBase + GlobalPosition3D(t * (rcs.first || 1.F))}; - vertices.emplace_back(m, TextureRelCoord {rcs.second, swing.z}, up); - } - } - mesh = defaultMesh(vertices); - } } RelativePosition3D @@ -176,3 +130,43 @@ RailLink::vehiclePositionOffset() const { return RAIL_HEIGHT; } + +template<> NetworkLinkHolder<RailLinkStraight>::NetworkLinkHolder() +{ + VertexArrayObject {vao} + .addAttribs<RailLinkStraight::Vertex, &RailLinkStraight::Vertex::a, &RailLinkStraight::Vertex::b, + &RailLinkStraight::Vertex::rotation, &RailLinkStraight::Vertex::textureRepeats>( + vertices.bufferName()); +} + +template<> NetworkLinkHolder<RailLinkCurve>::NetworkLinkHolder() +{ + VertexArrayObject {vao} + .addAttribs<RailLinkCurve::Vertex, &RailLinkCurve::Vertex::a, &RailLinkCurve::Vertex::b, + &RailLinkCurve::Vertex::c, &RailLinkCurve::Vertex::textureRepeats, &RailLinkCurve::Vertex::aangle, + &RailLinkCurve::Vertex::bangle, &RailLinkCurve::Vertex::radius>(vertices.bufferName()); +} + +namespace { + template<typename LinkType> + void + renderType(const NetworkLinkHolder<LinkType> & n, auto & s) + { + if (auto count = n.vertices.size()) { + s.use(railCrossSection, railTexturePos); + glBindVertexArray(n.vao); + glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(count)); + } + }; +} + +void +RailLinks::render(const SceneShader & shader) const +{ + if (!links.objects.empty()) { + texture->bind(); + renderType<RailLinkStraight>(*this, shader.networkStraight); + renderType<RailLinkCurve>(*this, shader.networkCurve); + glBindVertexArray(0); + } +} diff --git a/game/network/rail.h b/game/network/rail.h index 986b0aa..c8effef 100644 --- a/game/network/rail.h +++ b/game/network/rail.h @@ -2,13 +2,11 @@ #include "chronology.h" #include "game/worldobject.h" -#include "gfx/models/mesh.h" #include "gfx/renderable.h" #include "link.h" #include "network.h" #include <glm/glm.hpp> #include <memory> -#include <span> #include <special_members.h> class SceneShader; @@ -19,7 +17,7 @@ struct Arc; class RailLinkStraight; class RailLinkCurve; -class RailLink : public virtual Link, public Renderable { +class RailLink : public virtual Link { public: RailLink() = default; inline ~RailLink() override = 0; @@ -27,40 +25,57 @@ public: using StraightLink = RailLinkStraight; using CurveLink = RailLinkCurve; - void render(const SceneShader &) const override; NO_COPY(RailLink); NO_MOVE(RailLink); protected: [[nodiscard]] RelativePosition3D vehiclePositionOffset() const override; - [[nodiscard]] static Mesh::Ptr defaultMesh(const std::span<Vertex> vertices); - - Mesh::Ptr mesh; }; RailLink::~RailLink() = default; +class RailLinks; + class RailLinkStraight : public RailLink, public LinkStraight { public: - RailLinkStraight(const Node::Ptr &, const Node::Ptr &); + RailLinkStraight(NetworkLinkHolder<RailLinkStraight> &, const Node::Ptr &, const Node::Ptr &); + + struct Vertex { + GlobalPosition3D a, b; + glm::mat2 rotation; + float textureRepeats; + }; private: - RailLinkStraight(Node::Ptr, Node::Ptr, const RelativePosition3D & diff); + RailLinkStraight(NetworkLinkHolder<RailLinkStraight> &, Node::Ptr, Node::Ptr, const RelativePosition3D & diff); + InstanceVertices<Vertex>::InstanceProxy instance; }; class RailLinkCurve : public RailLink, public LinkCurve { public: - RailLinkCurve(const Node::Ptr &, const Node::Ptr &, GlobalPosition2D); + RailLinkCurve(NetworkLinkHolder<RailLinkCurve> &, const Node::Ptr &, const Node::Ptr &, GlobalPosition2D); + + struct Vertex { + GlobalPosition3D a, b, c; + float textureRepeats; + float aangle, bangle, radius; + }; private: - RailLinkCurve(const Node::Ptr &, const Node::Ptr &, GlobalPosition3D, const Arc); + RailLinkCurve( + NetworkLinkHolder<RailLinkCurve> &, const Node::Ptr &, const Node::Ptr &, GlobalPosition3D, const Arc); + InstanceVertices<Vertex>::InstanceProxy instance; }; -class RailLinks : public NetworkOf<RailLink>, public WorldObject { +template<> NetworkLinkHolder<RailLinkStraight>::NetworkLinkHolder(); +template<> NetworkLinkHolder<RailLinkCurve>::NetworkLinkHolder(); + +class RailLinks : public NetworkOf<RailLink, RailLinkStraight, RailLinkCurve>, public WorldObject { public: RailLinks(); std::shared_ptr<RailLink> addLinksBetween(GlobalPosition3D start, GlobalPosition3D end); + void render(const SceneShader &) const override; private: void tick(TickDuration elapsed) override; |