diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-02-24 01:28:14 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-02-24 01:28:14 +0000 |
commit | ef08a08617a1541d8aa1862d8bcfe049dcb57998 (patch) | |
tree | abfcb0e0146a29deead395b0a730acaf8b01dc47 /game/network | |
parent | Merge branch 'terrain-deform-2' (diff) | |
parent | New hardcoded test rail network (diff) | |
download | ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.tar.bz2 ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.tar.xz ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.zip |
Merge remote-tracking branch 'origin/terrain-for-networks'
Diffstat (limited to 'game/network')
-rw-r--r-- | game/network/link.cpp | 35 | ||||
-rw-r--r-- | game/network/link.h | 9 | ||||
-rw-r--r-- | game/network/network.cpp | 12 | ||||
-rw-r--r-- | game/network/network.h | 19 | ||||
-rw-r--r-- | game/network/network.impl.h | 65 | ||||
-rw-r--r-- | game/network/rail.cpp | 86 | ||||
-rw-r--r-- | game/network/rail.h | 7 |
7 files changed, 175 insertions, 58 deletions
diff --git a/game/network/link.cpp b/game/network/link.cpp index 79af92a..c84524c 100644 --- a/game/network/link.cpp +++ b/game/network/link.cpp @@ -38,6 +38,20 @@ LinkStraight::intersectRay(const Ray<GlobalPosition3D> & ray) const std::array {GlobalPosition3D {ends.front().node->pos}, GlobalPosition3D {ends.back().node->pos}}, 1000); } +std::vector<GlobalPosition3D> +LinkStraight::getBase(RelativeDistance width) const +{ + const auto start = ends.front().node->pos; + const auto end = ends.back().node->pos; + const auto direction = (vector_normal(normalize(::difference(start, end).xy())) * width / 2.F) || 0.F; + return { + start - direction, + start + direction, + end - direction, + end + direction, + }; +} + Location LinkCurve::positionAt(float dist, unsigned char start) const { @@ -73,3 +87,24 @@ LinkCurve::intersectRay(const Ray<GlobalPosition3D> & ray) const } return ray.passesCloseToEdges(points, 1.F); } + +std::vector<GlobalPosition3D> +LinkCurve::getBase(RelativeDistance width) const +{ + const auto start = ends.front().node->pos; + const auto end = ends.back().node->pos; + const auto segs = std::ceil(std::sqrt(radius) * 0.02F * arc.length()); + const auto step {glm::vec<2, RelativeDistance> {arc.length(), end.z - start.z} / segs}; + + auto segCount = static_cast<size_t>(segs) + 1; + std::vector<GlobalPosition3D> out; + out.reserve(segCount); + for (RelativePosition2D swing = {arc.first, centreBase.z - start.z}; segCount != 0U; swing += step, --segCount) { + const auto direction = sincos(swing.x); + const auto linkCentre = centreBase + ((direction * radius) || swing.y); + const auto toEdge = (direction * width / 2.F) || 0.F; + out.emplace_back(linkCentre + toEdge); + out.emplace_back(linkCentre - toEdge); + } + return out; +} diff --git a/game/network/link.h b/game/network/link.h index 725e023..59bbb65 100644 --- a/game/network/link.h +++ b/game/network/link.h @@ -16,7 +16,7 @@ template<typename> class Ray; // it has location class Node : public StdTypeDefs<Node> { public: - explicit Node(GlobalPosition3D p) noexcept : pos(p) {}; + explicit Node(GlobalPosition3D p) noexcept : pos(p) { }; virtual ~Node() noexcept = default; NO_COPY(Node); NO_MOVE(Node); @@ -38,13 +38,14 @@ public: Nexts nexts {}; }; - Link(End, End, float); + Link(End, End, RelativeDistance length); virtual ~Link() = default; NO_COPY(Link); NO_MOVE(Link); [[nodiscard]] virtual Location positionAt(RelativeDistance dist, unsigned char start) const = 0; [[nodiscard]] virtual bool intersectRay(const Ray<GlobalPosition3D> &) const = 0; + [[nodiscard]] virtual std::vector<GlobalPosition3D> getBase(RelativeDistance width) const = 0; std::array<End, 2> ends; float length; @@ -69,6 +70,7 @@ public: [[nodiscard]] Location positionAt(RelativeDistance dist, unsigned char start) const override; [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &) const override; + [[nodiscard]] std::vector<GlobalPosition3D> getBase(RelativeDistance width) const override; }; LinkStraight::~LinkStraight() = default; @@ -76,12 +78,13 @@ LinkStraight::~LinkStraight() = default; class LinkCurve : public virtual Link { public: inline ~LinkCurve() override = 0; - LinkCurve(GlobalPosition3D, RelativeDistance, Arc); + LinkCurve(GlobalPosition3D centreBase, RelativeDistance radius, Arc); NO_COPY(LinkCurve); NO_MOVE(LinkCurve); [[nodiscard]] Location positionAt(RelativeDistance dist, unsigned char start) const override; [[nodiscard]] bool intersectRay(const Ray<GlobalPosition3D> &) const override; + [[nodiscard]] std::vector<GlobalPosition3D> getBase(RelativeDistance width) const override; GlobalPosition3D centreBase; RelativeDistance radius; diff --git a/game/network/network.cpp b/game/network/network.cpp index 6ba3ed6..e67942f 100644 --- a/game/network/network.cpp +++ b/game/network/network.cpp @@ -8,7 +8,13 @@ #include <stdexcept> #include <utility> -Network::Network(const std::string & tn) : texture {std::make_shared<Texture>(tn)} { } +Network::Network(const std::string & tn) : + texture {std::make_shared<Texture>(tn, + TextureOptions { + .minFilter = GL_NEAREST_MIPMAP_LINEAR, + })} +{ +} Node::Ptr Network::nodeAt(GlobalPosition3D pos) @@ -115,8 +121,8 @@ Network::genCurveDef(const GlobalPosition3D & start, const GlobalPosition3D & en endDir += pi; const auto flatStart {start.xy()}, flatEnd {end.xy()}; auto midheight = [&](auto mid) { - const auto sm = glm::length(RelativePosition2D(flatStart - mid)), - em = glm::length(RelativePosition2D(flatEnd - mid)); + const auto sm = ::distance<2>(flatStart, mid); + const auto em = ::distance<2>(flatEnd, mid); return start.z + GlobalDistance(RelativeDistance(end.z - start.z) * (sm / (sm + em))); }; if (const auto radii = find_arcs_radius(flatStart, startDir, flatEnd, endDir); radii.first < radii.second) { diff --git a/game/network/network.h b/game/network/network.h index be0900b..291c4ec 100644 --- a/game/network/network.h +++ b/game/network/network.h @@ -14,6 +14,8 @@ #include <utility> class SceneShader; +struct Surface; +class GeoData; template<typename> class Ray; template<size_t... n> using GenDef = std::tuple<glm::vec<n, GlobalDistance>...>; @@ -41,12 +43,15 @@ public: virtual Link::CCollection candidateStraight(GlobalPosition3D, GlobalPosition3D) = 0; virtual Link::CCollection candidateJoins(GlobalPosition3D, GlobalPosition3D) = 0; virtual Link::CCollection candidateExtend(GlobalPosition3D, GlobalPosition3D) = 0; - virtual Link::CCollection addStraight(GlobalPosition3D, GlobalPosition3D) = 0; - virtual Link::CCollection addJoins(GlobalPosition3D, GlobalPosition3D) = 0; - virtual Link::CCollection addExtend(GlobalPosition3D, GlobalPosition3D) = 0; + virtual Link::CCollection addStraight(const GeoData *, GlobalPosition3D, GlobalPosition3D) = 0; + virtual Link::CCollection addJoins(const GeoData *, GlobalPosition3D, GlobalPosition3D) = 0; + virtual Link::CCollection addExtend(const GeoData *, GlobalPosition3D, GlobalPosition3D) = 0; [[nodiscard]] virtual float findNodeDirection(Node::AnyCPtr) const = 0; + [[nodiscard]] virtual const Surface * getBaseSurface() const = 0; + [[nodiscard]] virtual RelativeDistance getBaseWidth() const = 0; + protected: static void joinLinks(const Link::Ptr & l, const Link::Ptr & ol); static GenCurveDef genCurveDef(const GlobalPosition3D & start, const GlobalPosition3D & end, float startDir); @@ -102,12 +107,12 @@ public: Link::CCollection candidateStraight(GlobalPosition3D n1, GlobalPosition3D n2) override; Link::CCollection candidateJoins(GlobalPosition3D, GlobalPosition3D) override; Link::CCollection candidateExtend(GlobalPosition3D, GlobalPosition3D) override; - Link::CCollection addStraight(GlobalPosition3D n1, GlobalPosition3D n2) override; - Link::CCollection addJoins(GlobalPosition3D, GlobalPosition3D) override; - Link::CCollection addExtend(GlobalPosition3D, GlobalPosition3D) override; + Link::CCollection addStraight(const GeoData *, GlobalPosition3D n1, GlobalPosition3D n2) override; + Link::CCollection addJoins(const GeoData *, GlobalPosition3D, GlobalPosition3D) override; + Link::CCollection addExtend(const GeoData *, GlobalPosition3D, GlobalPosition3D) override; [[nodiscard]] float findNodeDirection(Node::AnyCPtr) const override; protected: - Link::CCollection addJoins(); + Link::CCollection addCurve(const GeoData *, const GenCurveDef &); }; diff --git a/game/network/network.impl.h b/game/network/network.impl.h index ff29088..c683378 100644 --- a/game/network/network.impl.h +++ b/game/network/network.impl.h @@ -1,4 +1,6 @@ +#include "collections.h" #include "network.h" +#include <game/geoData.h> #include <gfx/gl/sceneShader.h> #include <gfx/models/texture.h> @@ -52,7 +54,7 @@ template<typename T, typename... Links> Link::CCollection NetworkOf<T, Links...>::candidateJoins(GlobalPosition3D start, GlobalPosition3D end) { - if (glm::length(RelativePosition3D(start - end)) < 2000.F) { + if (::distance(start, end) < 2000.F) { return {}; } const auto defs = genCurveDef( @@ -72,28 +74,69 @@ NetworkOf<T, Links...>::candidateExtend(GlobalPosition3D start, GlobalPosition3D template<typename T, typename... Links> Link::CCollection -NetworkOf<T, Links...>::addStraight(GlobalPosition3D n1, GlobalPosition3D n2) +NetworkOf<T, Links...>::addStraight(const GeoData * geoData, GlobalPosition3D n1, GlobalPosition3D n2) { - return {addLink<typename T::StraightLink>(n1, n2)}; + Link::CCollection out; + geoData->walk(n1.xy(), n2, [geoData, &out, this, &n1](const GeoData::WalkStep & step) { + if (step.previous.is_valid() && geoData->getSurface(step.current) != geoData->getSurface(step.previous)) { + const auto surfaceEdgePosition = geoData->positionAt(GeoData::PointFace(step.exitPosition, step.current)); + out.emplace_back(addLink<typename T::StraightLink>(n1, surfaceEdgePosition)); + n1 = surfaceEdgePosition; + } + }); + out.emplace_back(addLink<typename T::StraightLink>(n1, n2)); + return out; +} + +template<typename T, typename... Links> +Link::CCollection +NetworkOf<T, Links...>::addCurve(const GeoData * geoData, const GenCurveDef & curve) +{ + auto [cstart, cend, centre] = curve; + Link::CCollection out; + std::set<GeoData::WalkStepCurve, SortedBy<&GeoData::WalkStepCurve::angle>> breaks; + const auto radiusMid = ::distance(cstart.xy(), centre); + for (const auto radiusOffset : {-getBaseWidth() / 2.F, 0.F, getBaseWidth() / 2.F}) { + const auto radius = radiusOffset + radiusMid; + const auto start = centre + (difference(cstart.xy(), centre) * radius) / radiusMid; + const auto end = centre + (difference(cend.xy(), centre) * radius) / radiusMid; + geoData->walk(start, end, centre, [geoData, &breaks](const GeoData::WalkStepCurve & step) { + if (step.previous.is_valid() && geoData->getSurface(step.current) != geoData->getSurface(step.previous)) { + breaks.insert(step); + } + }); + } + std::vector<GlobalPosition3D> points; + points.reserve(breaks.size() + 2); + points.push_back(cstart); + std::ranges::transform( + breaks, std::back_inserter(points), [geoData, centre, radiusMid](const GeoData::WalkStepCurve & step) { + return (centre + (sincos(step.angle) * radiusMid)) + || geoData->positionAt(GeoData::PointFace(step.exitPosition, step.current)).z; + }); + points.push_back(cend); + mergeClose(points, ::distance<3, GlobalDistance>, ::midpoint<3, GlobalDistance>, 2'000.F); + std::ranges::transform(points | std::views::pairwise, std::back_inserter(out), [this, centre](const auto pair) { + const auto [a, b] = pair; + return addLink<typename T::CurveLink>(a, b, centre); + }); + return out; } template<typename T, typename... Links> Link::CCollection -NetworkOf<T, Links...>::addJoins(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::addJoins(const GeoData * geoData, GlobalPosition3D start, GlobalPosition3D end) { - if (glm::length(RelativePosition3D(start - end)) < 2000.F) { + if (::distance(start, end) < 2000.F) { return {}; } const auto defs = genCurveDef(start, end, findNodeDirection(nodeAt(start)), findNodeDirection(nodeAt(end))); - const auto & [c1s, c1e, c1c] = defs.first; - const auto & [c2s, c2e, c2c] = defs.second; - return {addLink<typename T::CurveLink>(c1s, c1e, c1c), addLink<typename T::CurveLink>(c2s, c2e, c2c)}; + return addCurve(geoData, defs.first) + addCurve(geoData, defs.second); } template<typename T, typename... Links> Link::CCollection -NetworkOf<T, Links...>::addExtend(GlobalPosition3D start, GlobalPosition3D end) +NetworkOf<T, Links...>::addExtend(const GeoData * geoData, GlobalPosition3D start, GlobalPosition3D end) { - const auto [cstart, cend, centre] = genCurveDef(start, end, findNodeDirection(nodeAt(start))); - return {addLink<typename T::CurveLink>(cstart, cend, centre)}; + return addCurve(geoData, genCurveDef(start, end, findNodeDirection(nodeAt(start)))); } diff --git a/game/network/rail.cpp b/game/network/rail.cpp index 6f04070..d7de231 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -1,4 +1,6 @@ #include "rail.h" +#include "game/gamestate.h" +#include "game/geoData.h" #include "network.h" #include <game/network/network.impl.h> // IWYU pragma: keep #include <gfx/gl/sceneShader.h> @@ -8,7 +10,7 @@ template class NetworkOf<RailLink, RailLinkStraight, RailLinkCurve>; constexpr auto RAIL_CROSSSECTION_VERTICES {5U}; -constexpr Size3D RAIL_HEIGHT {0, 0, 250.F}; +constexpr Size3D RAIL_HEIGHT {0, 0, 50.F}; RailLinks::RailLinks() : NetworkOf<RailLink, RailLinkStraight, RailLinkCurve> {"rails.jpg"} { } @@ -38,8 +40,8 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) const auto flatStart {start.xy()}, flatEnd {end.xy()}; if (node2ins.second == NodeIs::InNetwork) { auto midheight = [&](auto mid) { - const auto sm = glm::length(RelativePosition2D(flatStart - mid)), - em = glm::length(RelativePosition2D(flatEnd - mid)); + const auto sm = ::distance<2>(flatStart, mid); + const auto em = ::distance<2>(flatEnd, mid); return start.z + GlobalDistance(RelativeDistance(end.z - start.z) * (sm / (sm + em))); }; const float dir2 = pi + findNodeDirection(node2ins.first); @@ -73,26 +75,31 @@ RailLinks::addLinksBetween(GlobalPosition3D start, GlobalPosition3D end) return addLink<RailLinkCurve>(start, end, centre.first); } -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 -round_sleepers(const float v) -{ - return round_frac(v, sleepers); +namespace { + constexpr const std::array<RelativePosition3D, RAIL_CROSSSECTION_VERTICES> RAIL_CROSS_SECTION {{ + {-1330.F, 0.F, 0}, + {-608.F, 0.F, RAIL_HEIGHT.z}, + {0, 0.F, RAIL_HEIGHT.z / 2}, + {608.F, 0.F, RAIL_HEIGHT.z}, + {1330.F, 0.F, 0}, + }}; + constexpr const std::array<float, RAIL_CROSSSECTION_VERTICES> RAIL_TEXTURE_POS { + 0.15F, + .34F, + .5F, + .66F, + 0.85F, + }; + template<std::floating_point T> constexpr T SLEEPERS_PER_TEXTURE {5}; + template<std::floating_point T> constexpr T TEXTURE_LENGTH {2'000}; + template<std::floating_point T> constexpr T SLEEPER_LENGTH {T {1} / SLEEPERS_PER_TEXTURE<T>}; + + template<std::floating_point T> + constexpr auto + roundSleepers(const T length) + { + return round_frac(length / TEXTURE_LENGTH<T>, SLEEPER_LENGTH<T>); + } } RailLinkStraight::RailLinkStraight(NetworkLinkHolder<RailLinkStraight> & instances, const Node::Ptr & a, @@ -104,22 +111,22 @@ 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))} + ends[0].node->pos, ends[1].node->pos, flat_orientation(diff), roundSleepers(length))} { } -RailLinkCurve::RailLinkCurve(NetworkLinkHolder<RailLinkCurve> & instances, const Node::Ptr & a, const Node::Ptr & b, - GlobalPosition2D c) : RailLinkCurve(instances, a, b, c || a->pos.z, {c, 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, ::distance<2>(a->pos.xy(), c), {c, a->pos, b->pos}) { } RailLinkCurve::RailLinkCurve(NetworkLinkHolder<RailLinkCurve> & instances, const Node::Ptr & a, const Node::Ptr & b, - GlobalPosition3D c, const Arc arc) : + GlobalPosition3D c, RelativeDistance radius, const Arc arc) : Link({a, normalize(arc.first + half_pi)}, {b, normalize(arc.second - half_pi)}, - glm::length(RelativePosition3D(a->pos - c)) * arc.length()), - 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)} + glm::length(RelativePosition2D {radius * arc.length(), difference(a->pos, b->pos).z})), + LinkCurve {c, radius, arc}, instance {instances.vertices.acquire(ends[0].node->pos, ends[1].node->pos, c, + roundSleepers(length), half_pi - arc.first, half_pi - arc.second, radius)} { } @@ -151,7 +158,7 @@ namespace { renderType(const NetworkLinkHolder<LinkType> & n, auto & s) { if (auto count = n.vertices.size()) { - s.use(railCrossSection, railTexturePos); + s.use(RAIL_CROSS_SECTION, RAIL_TEXTURE_POS); glBindVertexArray(n.vao); glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(count)); } @@ -163,8 +170,23 @@ RailLinks::render(const SceneShader & shader) const { if (!links.objects.empty()) { texture->bind(); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1, 0); renderType<RailLinkStraight>(*this, shader.networkStraight); renderType<RailLinkCurve>(*this, shader.networkCurve); + glDisable(GL_POLYGON_OFFSET_FILL); glBindVertexArray(0); } } + +const Surface * +RailLinks::getBaseSurface() const +{ + return std::dynamic_pointer_cast<Surface>(gameState->assets.at("terrain.surface.gravel")).get(); +} + +RelativeDistance +RailLinks::getBaseWidth() const +{ + return 5'700; +} diff --git a/game/network/rail.h b/game/network/rail.h index c8effef..fa64eda 100644 --- a/game/network/rail.h +++ b/game/network/rail.h @@ -62,8 +62,8 @@ public: }; private: - RailLinkCurve( - NetworkLinkHolder<RailLinkCurve> &, const Node::Ptr &, const Node::Ptr &, GlobalPosition3D, const Arc); + RailLinkCurve(NetworkLinkHolder<RailLinkCurve> &, const Node::Ptr &, const Node::Ptr &, GlobalPosition3D centreBase, + RelativeDistance radius, Arc); InstanceVertices<Vertex>::InstanceProxy instance; }; @@ -77,6 +77,9 @@ public: std::shared_ptr<RailLink> addLinksBetween(GlobalPosition3D start, GlobalPosition3D end); void render(const SceneShader &) const override; + [[nodiscard]] const Surface * getBaseSurface() const override; + [[nodiscard]] RelativeDistance getBaseWidth() const override; + private: void tick(TickDuration elapsed) override; }; |