diff options
Diffstat (limited to 'game')
-rw-r--r-- | game/geoData.cpp | 101 | ||||
-rw-r--r-- | game/geoData.h | 28 | ||||
-rw-r--r-- | game/network/network.cpp | 8 | ||||
-rw-r--r-- | game/network/rail.cpp | 57 | ||||
-rw-r--r-- | game/terrain.cpp | 4 |
5 files changed, 135 insertions, 63 deletions
diff --git a/game/geoData.cpp b/game/geoData.cpp index d8caff7..f0e38d0 100644 --- a/game/geoData.cpp +++ b/game/geoData.cpp @@ -236,12 +236,12 @@ GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const GeoData::IntersectionResult out; walkUntil(PointFace {ray.start, face}, ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())), - [&out, &ray, this](FaceHandle face) { + [&out, &ray, this](const auto & step) { BaryPosition bari {}; RelativeDistance dist {}; - const auto t = triangle<3>(face); + const auto t = triangle<3>(step.current); if (ray.intersectTriangle(t.x, t.y, t.z, bari, dist)) { - out.emplace(t * bari, face); + out.emplace(t * bari, step.current); return true; } return false; @@ -250,7 +250,7 @@ GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const } void -GeoData::walk(const PointFace & from, const GlobalPosition2D to, const std::function<void(FaceHandle)> & op) const +GeoData::walk(const PointFace & from, const GlobalPosition2D to, Consumer<WalkStep> op) const { walkUntil(from, to, [&op](const auto & fh) { op(fh); @@ -259,41 +259,86 @@ GeoData::walk(const PointFace & from, const GlobalPosition2D to, const std::func } void -GeoData::walkUntil(const PointFace & from, const GlobalPosition2D to, const std::function<bool(FaceHandle)> & op) const +GeoData::walkUntil(const PointFace & from, const GlobalPosition2D to, Tester<WalkStep> op) const { - auto f = from.face(this); - if (!f.is_valid()) { + WalkStep step { + .current = from.face(this), + }; + if (!step.current.is_valid()) { const auto entryEdge = findEntry(from.point, to); if (!entryEdge.is_valid()) { return; } - f = opposite_face_handle(entryEdge); + step.current = opposite_face_handle(entryEdge); } - FaceHandle previousFace; - while (f.is_valid() && !op(f)) { - for (auto next = cfh_iter(f); next.is_valid(); ++next) { - f = opposite_face_handle(*next); - if (f.is_valid() && f != previousFace) { - const auto e1 = point(to_vertex_handle(*next)); - const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(*next))); + while (step.current.is_valid() && !op(step)) { + step.previous = step.current; + for (const auto next : fh_range(step.current)) { + step.current = opposite_face_handle(next); + if (step.current.is_valid() && step.current != step.previous) { + const auto e1 = point(to_vertex_handle(next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(next))); if (linesCrossLtR(from.point, to, e1, e2)) { - previousFace = f; + step.exitHalfedge = next; + step.exitPosition = linesIntersectAt(from.point.xy(), to.xy(), e1.xy(), e2.xy()).value(); break; } } - f.reset(); + step.current.reset(); } } } void -GeoData::boundaryWalk(const std::function<void(HalfedgeHandle)> & op) const +GeoData::walk(const PointFace & from, GlobalPosition2D to, GlobalPosition2D centre, Consumer<WalkStep> op) const +{ + walkUntil(from, to, centre, [&op](const auto & fh) { + op(fh); + return false; + }); +} + +void +GeoData::walkUntil(const PointFace & from, GlobalPosition2D to, GlobalPosition2D centre, Tester<WalkStep> op) const +{ + WalkStep step { + .current = from.face(this), + }; + if (!step.current.is_valid()) { + const auto entryEdge = findEntry(from.point, to); + if (!entryEdge.is_valid()) { + return; + } + step.current = opposite_face_handle(entryEdge); + } + ArcSegment arc {centre, from.point, to}; + while (step.current.is_valid() && !op(step)) { + step.previous = step.current; + for (const auto next : fh_range(step.current)) { + step.current = opposite_face_handle(next); + if (step.current.is_valid()) { + const auto e1 = point(to_vertex_handle(next)); + const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(next))); + if (const auto intersect = arc.crossesLineAt(e1, e2)) { + step.exitHalfedge = next; + arc.ep0 = step.exitPosition = intersect.value().first; + arc.first = std::nextafter(intersect.value().second, INFINITY); + break; + } + } + step.current.reset(); + } + } +} + +void +GeoData::boundaryWalk(Consumer<HalfedgeHandle> op) const { boundaryWalk(op, findBoundaryStart()); } void -GeoData::boundaryWalk(const std::function<void(HalfedgeHandle)> & op, HalfedgeHandle start) const +GeoData::boundaryWalk(Consumer<HalfedgeHandle> op, HalfedgeHandle start) const { assert(is_boundary(start)); boundaryWalkUntil( @@ -305,13 +350,13 @@ GeoData::boundaryWalk(const std::function<void(HalfedgeHandle)> & op, HalfedgeHa } void -GeoData::boundaryWalkUntil(const std::function<bool(HalfedgeHandle)> & op) const +GeoData::boundaryWalkUntil(Tester<HalfedgeHandle> op) const { boundaryWalkUntil(op, findBoundaryStart()); } void -GeoData::boundaryWalkUntil(const std::function<bool(HalfedgeHandle)> & op, HalfedgeHandle start) const +GeoData::boundaryWalkUntil(Tester<HalfedgeHandle> op, HalfedgeHandle start) const { assert(is_boundary(start)); if (!op(start)) { @@ -468,10 +513,10 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const if (!inter) { throw std::runtime_error("Perpendicular lines do not cross"); } - return split(edge_handle(nearest.first), *inter || tsPoint.z); + return split_copy(edge_handle(nearest.first), *inter || tsPoint.z); } // Nothing close, split face - return split(face, tsPoint); + return split_copy(face, tsPoint); }; // New vertices for each vertex in triangleStrip @@ -524,7 +569,7 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const return true; } else { - start = split(edge_handle(next), positionOnTriangle(*intersection, triangle)); + start = split_copy(edge_handle(next), positionOnTriangle(*intersection, triangle)); } addVertexForNormalUpdate(start); boundaryTriangles.emplace(start, &triangle); @@ -545,8 +590,8 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const triangle++; }; std::ranges::for_each(newVerts | std::views::adjacent<3>, doBoundary); - doBoundaryPart(*++newVerts.begin(), newVerts.front(), *strip.rbegin()); - doBoundaryPart(*++newVerts.rbegin(), newVerts.back(), *strip.rbegin()); + doBoundaryPart(*++newVerts.begin(), newVerts.front(), strip.front()); + doBoundaryPart(*++newVerts.rbegin(), newVerts.back(), strip.back()); std::set<HalfedgeHandle> done; std::set<HalfedgeHandle> todo; @@ -600,7 +645,9 @@ GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip, const }); } }; - surfaceStripWalk(surfaceStripWalk, findPoint(strip.front().centroid())); + for (const auto & triangle : strip) { + surfaceStripWalk(surfaceStripWalk, findPoint(triangle.centroid())); + } updateAllVertexNormals(newOrChangedVerts); generation++; diff --git a/game/geoData.h b/game/geoData.h index 92b9b75..e3fc313 100644 --- a/game/geoData.h +++ b/game/geoData.h @@ -64,13 +64,25 @@ public: [[nodiscard]] IntersectionResult intersectRay(const Ray<GlobalPosition3D> &) const; [[nodiscard]] IntersectionResult intersectRay(const Ray<GlobalPosition3D> &, FaceHandle start) const; - void walk(const PointFace & from, const GlobalPosition2D to, const std::function<void(FaceHandle)> & op) const; - void walkUntil(const PointFace & from, const GlobalPosition2D to, const std::function<bool(FaceHandle)> & op) const; + struct WalkStep { + FaceHandle current; + FaceHandle previous {}; + HalfedgeHandle exitHalfedge {}; + GlobalPosition2D exitPosition {}; + }; + + template<typename T> using Consumer = const std::function<void(const T &)> &; + template<typename T> using Tester = const std::function<bool(const T &)> &; + + void walk(const PointFace & from, GlobalPosition2D to, Consumer<WalkStep> op) const; + void walkUntil(const PointFace & from, GlobalPosition2D to, Tester<WalkStep> op) const; + void walk(const PointFace & from, GlobalPosition2D to, GlobalPosition2D centre, Consumer<WalkStep> op) const; + void walkUntil(const PointFace & from, GlobalPosition2D to, GlobalPosition2D centre, Tester<WalkStep> op) const; - void boundaryWalk(const std::function<void(HalfedgeHandle)> &) const; - void boundaryWalk(const std::function<void(HalfedgeHandle)> &, HalfedgeHandle start) const; - void boundaryWalkUntil(const std::function<bool(HalfedgeHandle)> &) const; - void boundaryWalkUntil(const std::function<bool(HalfedgeHandle)> &, HalfedgeHandle start) const; + void boundaryWalk(Consumer<HalfedgeHandle>) const; + void boundaryWalk(Consumer<HalfedgeHandle>, HalfedgeHandle start) const; + void boundaryWalkUntil(Tester<HalfedgeHandle>) const; + void boundaryWalkUntil(Tester<HalfedgeHandle>, HalfedgeHandle start) const; [[nodiscard]] HalfedgeHandle findEntry(const GlobalPosition2D from, const GlobalPosition2D to) const; @@ -94,9 +106,9 @@ public: template<typename HandleT> [[nodiscard]] auto - get_surface(const HandleT h) + getSurface(const HandleT handle) const { - return property(surface, h); + return property(surface, handle); } void sanityCheck() const; diff --git a/game/network/network.cpp b/game/network/network.cpp index 6ba3ed6..1666c4d 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) diff --git a/game/network/rail.cpp b/game/network/rail.cpp index dc62cf3..2820cca 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -75,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, -RAIL_HEIGHT.z * 2}, - {-608.F, 0.F, RAIL_HEIGHT.z}, - {0, 0.F, RAIL_HEIGHT.z / 2}, - {608.F, 0.F, RAIL_HEIGHT.z}, - {1900.F, 0.F, -RAIL_HEIGHT.z * 2}, -}}; -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, @@ -106,7 +111,7 @@ 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))} { } @@ -120,9 +125,8 @@ RailLinkCurve::RailLinkCurve(NetworkLinkHolder<RailLinkCurve> & instances, const GlobalPosition3D c, RelativeDistance radius, const Arc arc) : Link({a, normalize(arc.first + half_pi)}, {b, normalize(arc.second - half_pi)}, 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, round_sleepers(length / 2000.F), - half_pi - arc.first, half_pi - arc.second, radius)} + 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)} { } @@ -154,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)); } @@ -166,8 +170,11 @@ 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); } } diff --git a/game/terrain.cpp b/game/terrain.cpp index e7508d0..39aa99a 100644 --- a/game/terrain.cpp +++ b/game/terrain.cpp @@ -43,7 +43,7 @@ Terrain::generateMeshes() [this, &vertexIndex, &vertices](const GeoData::VertexHandle v) { std::for_each(geoData->vf_begin(v), geoData->vf_end(v), [&vertexIndex, v, this, &vertices](const GeoData::FaceHandle f) { - const auto surface = geoData->get_surface(f); + const auto surface = geoData->getSurface(f); if (const auto vertexIndexRef = vertexIndex.emplace(std::make_pair(v, surface), 0); vertexIndexRef.second) { vertexIndexRef.first->second = vertices.size(); @@ -57,7 +57,7 @@ Terrain::generateMeshes() geoData->faces_sbegin(), geoData->faces_end(), [this, &vertexIndex, &indices](const GeoData::FaceHandle f) { std::transform(geoData->fv_begin(f), geoData->fv_end(f), std::back_inserter(indices), [&vertexIndex, f, this](const GeoData::VertexHandle v) { - return vertexIndex[std::make_pair(v, geoData->get_surface(f))]; + return vertexIndex[std::make_pair(v, geoData->getSurface(f))]; }); }); meshes.create<MeshT<Vertex>>(vertices, indices); |