summaryrefslogtreecommitdiff
path: root/game/network
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2025-02-24 01:28:14 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2025-02-24 01:28:14 +0000
commitef08a08617a1541d8aa1862d8bcfe049dcb57998 (patch)
treeabfcb0e0146a29deead395b0a730acaf8b01dc47 /game/network
parentMerge branch 'terrain-deform-2' (diff)
parentNew hardcoded test rail network (diff)
downloadilt-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.cpp35
-rw-r--r--game/network/link.h9
-rw-r--r--game/network/network.cpp12
-rw-r--r--game/network/network.h19
-rw-r--r--game/network/network.impl.h65
-rw-r--r--game/network/rail.cpp86
-rw-r--r--game/network/rail.h7
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;
};