summaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2024-04-04 20:06:36 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2024-04-04 20:06:36 +0100
commit30b027f84772d4b1d18eebd03b83ce3a5966d5fe (patch)
treebf1f424ee3c92516d652934cf502ee06f60c57e5 /game
parentSimplify vector addition/subtraction with differnt types (diff)
parentRemove wireframe mode from test renders (diff)
downloadilt-30b027f84772d4b1d18eebd03b83ce3a5966d5fe.tar.bz2
ilt-30b027f84772d4b1d18eebd03b83ce3a5966d5fe.tar.xz
ilt-30b027f84772d4b1d18eebd03b83ce3a5966d5fe.zip
Merge remote-tracking branch 'origin/deform-terrain'
Two related issues remain: * Terrain self shadowing is common and handled poorly * Odd, but mathematically correct patterns/stripes in feature boundaries Neither of these relate directly to deformation.
Diffstat (limited to 'game')
-rw-r--r--game/geoData.cpp359
-rw-r--r--game/geoData.h87
-rw-r--r--game/network/link.cpp2
-rw-r--r--game/network/rail.cpp12
-rw-r--r--game/terrain.cpp6
5 files changed, 435 insertions, 31 deletions
diff --git a/game/geoData.cpp b/game/geoData.cpp
index 359e8c0..ed4303b 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -1,7 +1,10 @@
#include "geoData.h"
+#include "collections.h"
+#include "geometricPlane.h"
#include <fstream>
#include <glm/gtx/intersect.hpp>
#include <maths.h>
+#include <set>
GeoData
GeoData::loadFromAsciiGrid(const std::filesystem::path & input)
@@ -62,6 +65,8 @@ GeoData::loadFromAsciiGrid(const std::filesystem::path & input)
return mesh;
};
+template<typename T> constexpr static T GRID_SIZE = 10'000;
+
GeoData
GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistance h)
{
@@ -70,11 +75,29 @@ GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistan
mesh.lowerExtent = {lower, h};
mesh.upperExtent = {upper, h};
- const auto ll = mesh.add_vertex({lower.x, lower.y, h}), lu = mesh.add_vertex({lower.x, upper.y, h}),
- ul = mesh.add_vertex({upper.x, lower.y, h}), uu = mesh.add_vertex({upper.x, upper.y, h});
+ std::vector<VertexHandle> vertices;
+ for (GlobalDistance row = lower.x; row < upper.x; row += GRID_SIZE<GlobalDistance>) {
+ for (GlobalDistance col = lower.y; col < upper.y; col += GRID_SIZE<GlobalDistance>) {
+ vertices.push_back(mesh.add_vertex({col, row, h}));
+ }
+ }
- mesh.add_face(ll, uu, lu);
- mesh.add_face(ll, ul, uu);
+ const auto nrows = static_cast<size_t>(std::ceil(float(upper.x - lower.x) / GRID_SIZE<RelativeDistance>));
+ const auto ncols = static_cast<size_t>(std::ceil(float(upper.y - lower.y) / GRID_SIZE<RelativeDistance>));
+ for (size_t row = 1; row < nrows; ++row) {
+ for (size_t col = 1; col < ncols; ++col) {
+ mesh.add_face({
+ vertices[ncols * (row - 1) + (col - 1)],
+ vertices[ncols * (row - 0) + (col - 0)],
+ vertices[ncols * (row - 0) + (col - 1)],
+ });
+ mesh.add_face({
+ vertices[ncols * (row - 1) + (col - 1)],
+ vertices[ncols * (row - 1) + (col - 0)],
+ vertices[ncols * (row - 0) + (col - 0)],
+ });
+ }
+ }
mesh.update_vertex_normals_only();
@@ -84,11 +107,11 @@ GeoData::createFlat(GlobalPosition2D lower, GlobalPosition2D upper, GlobalDistan
OpenMesh::FaceHandle
GeoData::findPoint(GlobalPosition2D p) const
{
- return findPoint(p, *faces_begin());
+ return findPoint(p, *faces_sbegin());
}
GeoData::PointFace::PointFace(const GlobalPosition2D p, const GeoData * mesh) :
- PointFace {p, mesh, *mesh->faces_begin()}
+ PointFace {p, mesh, *mesh->faces_sbegin()}
{
}
@@ -112,7 +135,7 @@ GeoData::PointFace::face(const GeoData * mesh, FaceHandle start) const
GeoData::FaceHandle
GeoData::PointFace::face(const GeoData * mesh) const
{
- return face(mesh, *mesh->faces_begin());
+ return face(mesh, *mesh->faces_sbegin());
}
namespace {
@@ -193,16 +216,16 @@ GeoData::positionAt(const PointFace & p) const
return positionOnTriangle(p.point, triangle<3>(p.face(this)));
}
-[[nodiscard]] std::optional<GlobalPosition3D>
+[[nodiscard]] GeoData::IntersectionResult
GeoData::intersectRay(const Ray<GlobalPosition3D> & ray) const
{
return intersectRay(ray, findPoint(ray.start));
}
-[[nodiscard]] std::optional<GlobalPosition3D>
+[[nodiscard]] GeoData::IntersectionResult
GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const
{
- std::optional<GlobalPosition3D> out;
+ GeoData::IntersectionResult out;
walkUntil(PointFace {ray.start, face},
ray.start.xy() + (ray.direction.xy() * RelativePosition2D(upperExtent.xy() - lowerExtent.xy())),
[&out, &ray, this](FaceHandle face) {
@@ -210,7 +233,7 @@ GeoData::intersectRay(const Ray<GlobalPosition3D> & ray, FaceHandle face) const
RelativeDistance dist {};
const auto t = triangle<3>(face);
if (ray.intersectTriangle(t.x, t.y, t.z, bari, dist)) {
- out = t * bari;
+ out.emplace(t * bari, face);
return true;
}
return false;
@@ -324,17 +347,321 @@ GeoData::triangleContainsPoint(const GlobalPosition2D p, FaceHandle face) const
GeoData::HalfedgeHandle
GeoData::findBoundaryStart() const
{
- return *std::find_if(halfedges_begin(), halfedges_end(), [this](const auto heh) {
+ return *std::find_if(halfedges_sbegin(), halfedges_end(), [this](const auto heh) {
return is_boundary(heh);
});
}
+[[nodiscard]] RelativePosition3D
+GeoData::difference(const HalfedgeHandle heh) const
+{
+ return point(to_vertex_handle(heh)) - point(from_vertex_handle(heh));
+}
+
+[[nodiscard]] RelativeDistance
+GeoData::length(const HalfedgeHandle heh) const
+{
+ return glm::length(difference(heh));
+}
+
+[[nodiscard]] GlobalPosition3D
+GeoData::centre(const HalfedgeHandle heh) const
+{
+ return point(from_vertex_handle(heh)) + (difference(heh) / 2.F);
+}
+
void
GeoData::update_vertex_normals_only()
{
- for (auto vh : all_vertices()) {
- Normal3D n;
- calc_vertex_normal_correct(vh, n);
- this->set_normal(vh, glm::normalize(n));
+ update_vertex_normals_only(vertices_sbegin());
+}
+
+void
+GeoData::update_vertex_normals_only(VertexIter start)
+{
+ std::for_each(start, vertices_end(), [this](const auto vh) {
+ if (normal(vh) == Normal3D {}) {
+ Normal3D n;
+ calc_vertex_normal_correct(vh, n);
+ this->set_normal(vh, glm::normalize(n));
+ }
+ });
+}
+
+bool
+GeoData::triangleOverlapsTriangle(const Triangle<2> & a, const Triangle<2> & b)
+{
+ return triangleContainsPoint(a.x, b) || triangleContainsPoint(a.y, b) || triangleContainsPoint(a.z, b)
+ || triangleContainsPoint(b.x, a) || triangleContainsPoint(b.y, a) || triangleContainsPoint(b.z, a)
+ || linesCross(a.x, a.y, b.x, b.y) || linesCross(a.x, a.y, b.y, b.z) || linesCross(a.x, a.y, b.z, b.x)
+ || linesCross(a.y, a.z, b.x, b.y) || linesCross(a.y, a.z, b.y, b.z) || linesCross(a.y, a.z, b.z, b.x)
+ || linesCross(a.z, a.x, b.x, b.y) || linesCross(a.z, a.x, b.y, b.z) || linesCross(a.z, a.x, b.z, b.x);
+}
+
+bool
+GeoData::triangleContainsTriangle(const Triangle<2> & a, const Triangle<2> & b)
+{
+ return triangleContainsPoint(a.x, b) && triangleContainsPoint(a.y, b) && triangleContainsPoint(a.z, b);
+}
+
+std::array<GeoData::FaceHandle, 4>
+GeoData::split(FaceHandle _fh)
+{
+ // Collect halfedges of face
+ const HalfedgeHandle he0 = halfedge_handle(_fh);
+ const HalfedgeHandle he1 = next_halfedge_handle(he0);
+ const HalfedgeHandle he2 = next_halfedge_handle(he1);
+
+ const EdgeHandle eh0 = edge_handle(he0);
+ const EdgeHandle eh1 = edge_handle(he1);
+ const EdgeHandle eh2 = edge_handle(he2);
+
+ // Collect points of face
+ const VertexHandle p0 = to_vertex_handle(he0);
+ const VertexHandle p1 = to_vertex_handle(he1);
+ const VertexHandle p2 = to_vertex_handle(he2);
+
+ // Calculate midpoint coordinates
+ const Point new0 = centre(he0);
+ const Point new1 = centre(he1);
+ const Point new2 = centre(he2);
+
+ // Add vertices at midpoint coordinates
+ const VertexHandle v0 = add_vertex(new0);
+ const VertexHandle v1 = add_vertex(new1);
+ const VertexHandle v2 = add_vertex(new2);
+
+ const bool split0 = !is_boundary(eh0);
+ const bool split1 = !is_boundary(eh1);
+ const bool split2 = !is_boundary(eh2);
+
+ // delete original face
+ delete_face(_fh, false);
+
+ // split boundary edges of deleted face ( if not boundary )
+ if (split0) {
+ split(eh0, v0);
+ }
+
+ if (split1) {
+ split(eh1, v1);
+ }
+
+ if (split2) {
+ split(eh2, v2);
+ }
+
+ // Retriangulate
+ return {
+ add_face(v0, p0, v1),
+ add_face(p2, v0, v2),
+ add_face(v2, v1, p1),
+ add_face(v2, v0, v1),
+ };
+}
+
+void
+GeoData::setHeights(const std::span<const GlobalPosition3D> triangleStrip)
+{
+ static const RelativeDistance MAX_SLOPE = 1.5F;
+ static const RelativeDistance MIN_ARC = 0.01F;
+
+ if (triangleStrip.size() < 3) {
+ return;
+ }
+
+ const auto initialVertexCount = static_cast<unsigned int>(n_vertices());
+
+ // Create new vertices
+ std::vector<VertexHandle> newVerts;
+ newVerts.reserve(newVerts.size());
+ std::transform(triangleStrip.begin(), triangleStrip.end(), std::back_inserter(newVerts), [this](const auto tsVert) {
+ return add_vertex(tsVert);
+ });
+ // Create new faces
+ std::for_each(strip_begin(newVerts), strip_end(newVerts), [this](const auto & newVert) {
+ const auto [a, b, c] = newVert;
+ add_face(a, b, c);
+ });
+ for (auto start = faces_sbegin(); std::any_of(start, faces_end(), [this, &start](const auto fh) {
+ static constexpr auto MAX_FACE_AREA = 100'000'000.F;
+ if (triangle<3>(fh).area() > MAX_FACE_AREA) {
+ split(fh);
+ start = FaceIter {*this, FaceHandle(fh), true};
+ return true;
+ }
+ return false;
+ });) {
+ ;
}
+
+ // Extrude corners
+ struct Extrusion {
+ VertexHandle boundaryVertex, extrusionVertex;
+ Direction3D lowerLimit, upperLimit;
+ };
+
+ std::vector<Extrusion> extrusionExtents;
+ boundaryWalk(
+ [this, &extrusionExtents](const auto boundaryHeh) {
+ const auto prevBoundaryHeh = prev_halfedge_handle(boundaryHeh);
+ const auto prevBoundaryVertex = from_vertex_handle(prevBoundaryHeh);
+ const auto boundaryVertex = from_vertex_handle(boundaryHeh);
+ const auto nextBoundaryVertex = to_vertex_handle(boundaryHeh);
+ const auto p0 = point(prevBoundaryVertex);
+ const auto p1 = point(boundaryVertex);
+ const auto p2 = point(nextBoundaryVertex);
+ const auto e0 = glm::normalize(vector_normal(RelativePosition2D(p1 - p0)));
+ const auto e1 = glm::normalize(vector_normal(RelativePosition2D(p2 - p1)));
+
+ const auto addExtrusionFor = [this, &extrusionExtents, boundaryVertex, p1](Direction2D direction) {
+ const auto doExtrusion = [this](VertexHandle & extrusionVertex, Direction2D direction,
+ GlobalPosition3D boundaryVertex, RelativeDistance vert) {
+ const auto extrusionDir = glm::normalize(direction || vert);
+
+ if (!extrusionVertex.is_valid()) {
+ if (const auto intersect = intersectRay({boundaryVertex, extrusionDir})) {
+ auto splitVertex = split(intersect->second, intersect->first);
+ extrusionVertex = splitVertex;
+ }
+ else if (const auto intersect
+ = intersectRay({boundaryVertex + GlobalPosition3D {1, 1, 0}, extrusionDir})) {
+ auto splitVertex = split(intersect->second, intersect->first);
+ extrusionVertex = splitVertex;
+ }
+ else if (const auto intersect
+ = intersectRay({boundaryVertex + GlobalPosition3D {1, 0, 0}, extrusionDir})) {
+ auto splitVertex = split(intersect->second, intersect->first);
+ extrusionVertex = splitVertex;
+ }
+ }
+
+ return extrusionDir;
+ };
+
+ VertexHandle extrusionVertex;
+ extrusionExtents.emplace_back(boundaryVertex, extrusionVertex,
+ doExtrusion(extrusionVertex, direction, p1, -MAX_SLOPE),
+ doExtrusion(extrusionVertex, direction, p1, MAX_SLOPE));
+ assert(extrusionVertex.is_valid());
+ };
+ if (const Arc arc {e0, e1}; arc.length() < MIN_ARC) {
+ addExtrusionFor(normalize(e0 + e1) / cosf(arc.length() / 2.F));
+ }
+ else if (arc.length() < pi) {
+ // Previous half edge end to current half end start arc tangents
+ const auto limit = std::ceil(arc.length() * 5.F / pi);
+ const auto inc = arc.length() / limit;
+ for (float step = 0; step <= limit; step += 1.F) {
+ addExtrusionFor(sincosf(arc.first + (step * inc)));
+ }
+ }
+ else {
+ // Single tangent bisecting the difference
+ addExtrusionFor(normalize(e0 + e1) / sinf((arc.length() - pi) / 2.F));
+ }
+ },
+ *voh_begin(newVerts.front()));
+
+ // Cut existing terrain
+ extrusionExtents.emplace_back(extrusionExtents.front()); // Circular next
+ std::vector<std::vector<VertexHandle>> boundaryFaces;
+ std::adjacent_find(extrusionExtents.begin(), extrusionExtents.end(),
+ [this, &boundaryFaces](const auto & first, const auto & second) {
+ const auto p0 = point(first.boundaryVertex);
+ const auto p1 = point(second.boundaryVertex);
+ const auto bdir = RelativePosition3D(p1 - p0);
+ const auto make_plane = [p0](auto y, auto z) {
+ return GeometricPlaneT<GlobalPosition3D> {p0, crossProduct(y, z)};
+ };
+ const auto planes = ((first.boundaryVertex == second.boundaryVertex)
+ ? std::array {make_plane(second.lowerLimit, first.lowerLimit),
+ make_plane(second.upperLimit, first.upperLimit),
+ }
+ : std::array {
+ make_plane(bdir, second.lowerLimit),
+ make_plane(bdir, second.upperLimit),
+ });
+ assert(planes.front().normal.z > 0.F);
+ assert(planes.back().normal.z > 0.F);
+
+ auto & out = boundaryFaces.emplace_back();
+ out.emplace_back(first.boundaryVertex);
+ out.emplace_back(first.extrusionVertex);
+ for (auto currentVertex = first.extrusionVertex;
+ !find_halfedge(currentVertex, second.extrusionVertex).is_valid();) {
+ [[maybe_unused]] const auto n = std::any_of(
+ voh_begin(currentVertex), voh_end(currentVertex), [&](const auto currentVertexOut) {
+ const auto next = next_halfedge_handle(currentVertexOut);
+ const auto nextVertex = to_vertex_handle(next);
+ const auto startVertex = from_vertex_handle(next);
+ if (nextVertex == *++out.rbegin()) {
+ // This half edge goes back to the previous vertex
+ return false;
+ }
+ const auto edge = edge_handle(next);
+ const auto ep0 = point(startVertex);
+ const auto ep1 = point(nextVertex);
+ if (planes.front().getRelation(ep1) == GeometricPlane::PlaneRelation::Below
+ || planes.back().getRelation(ep1) == GeometricPlane::PlaneRelation::Above) {
+ return false;
+ }
+ const auto diff = RelativePosition3D(ep1 - ep0);
+ const auto length = glm::length(diff);
+ const auto dir = diff / length;
+ const Ray r {ep1, -dir};
+ const auto dists = planes * [r](const auto & plane) {
+ RelativeDistance dist {};
+ if (r.intersectPlane(plane.origin, plane.normal, dist)) {
+ return dist;
+ }
+ return INFINITY;
+ };
+ const auto dist = *std::min_element(dists.begin(), dists.end());
+ const auto splitPos = ep1 - (dir * dist);
+ if (dist <= length) {
+ currentVertex = split(edge, splitPos);
+ out.emplace_back(currentVertex);
+ return true;
+ }
+ return false;
+ });
+ assert(n);
+ }
+ out.emplace_back(second.extrusionVertex);
+ if (first.boundaryVertex != second.boundaryVertex) {
+ out.emplace_back(second.boundaryVertex);
+ }
+ return false;
+ });
+
+ // Remove old faces
+ std::set<FaceHandle> visited;
+ auto removeOld = [&](auto & self, const auto face) -> void {
+ if (visited.insert(face).second) {
+ std::for_each(fh_begin(face), fh_end(face), [&](const auto fh) {
+ const auto b1 = to_vertex_handle(fh);
+ const auto b2 = from_vertex_handle(fh);
+ if (opposite_face_handle(fh).is_valid()
+ && std::none_of(boundaryFaces.begin(), boundaryFaces.end(), [b2, b1](const auto & bf) {
+ return std::adjacent_find(bf.begin(), bf.end(), [b2, b1](const auto v1, const auto v2) {
+ return b1 == v1 && b2 == v2;
+ }) != bf.end();
+ })) {
+ self(self, opposite_face_handle(fh));
+ }
+ });
+
+ delete_face(face, false);
+ }
+ };
+ removeOld(removeOld, findPoint(triangleStrip.front()));
+
+ std::for_each(boundaryFaces.begin(), boundaryFaces.end(), [&](auto & boundaryFace) {
+ std::reverse(boundaryFace.begin(), boundaryFace.end());
+ add_face(boundaryFace);
+ });
+
+ // Tidy up
+ update_vertex_normals_only(VertexIter {*this, vertex_handle(initialVertexCount), true});
}
diff --git a/game/geoData.h b/game/geoData.h
index 15143e8..021b4c7 100644
--- a/game/geoData.h
+++ b/game/geoData.h
@@ -61,11 +61,69 @@ public:
});
}
+ [[nodiscard]]
glm::vec<Dim, GlobalDistance>
operator*(BaryPosition bari) const
{
- const auto & t {*this};
- return t[0] + (RelativePosition<Dim>(t[1] - t[0]) * bari.x) + (RelativePosition<Dim>(t[2] - t[1]) * bari.y);
+ return p(0) + (difference(p(0), p(1)) * bari.x) + (difference(p(0), p(2)) * bari.y);
+ }
+
+ [[nodiscard]]
+ auto
+ area() const
+ requires(Dim == 3)
+ {
+ return glm::length(crossProduct(difference(p(0), p(1)), difference(p(0), p(2)))) / 2.F;
+ }
+
+ [[nodiscard]]
+ Normal3D
+ normal() const
+ requires(Dim == 3)
+ {
+ return crossProduct(difference(p(0), p(1)), difference(p(0), p(2)));
+ }
+
+ [[nodiscard]]
+ Normal3D
+ nnormal() const
+ requires(Dim == 3)
+ {
+ return glm::normalize(normal());
+ }
+
+ [[nodiscard]]
+ auto
+ angle(glm::length_t c) const
+ {
+ return Arc {P(c), P(c + 2), P(c + 1)}.length();
+ }
+
+ template<glm::length_t D = Dim>
+ [[nodiscard]]
+ auto
+ angleAt(const GlobalPosition<D> pos) const
+ requires(D <= Dim)
+ {
+ for (glm::length_t i {}; i < 3; ++i) {
+ if (GlobalPosition<D> {p(i)} == pos) {
+ return angle(i);
+ }
+ }
+ return 0.F;
+ }
+
+ [[nodiscard]]
+ inline auto
+ p(const glm::length_t i) const
+ {
+ return base::operator[](i);
+ }
+
+ [[nodiscard]] inline auto
+ P(const glm::length_t i) const
+ {
+ return base::operator[](i % 3);
}
};
@@ -73,8 +131,10 @@ public:
[[nodiscard]] FaceHandle findPoint(GlobalPosition2D, FaceHandle start) const;
[[nodiscard]] GlobalPosition3D positionAt(const PointFace &) const;
- [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray<GlobalPosition3D> &) const;
- [[nodiscard]] std::optional<GlobalPosition3D> intersectRay(const Ray<GlobalPosition3D> &, FaceHandle start) const;
+ using IntersectionLocation = std::pair<GlobalPosition3D, FaceHandle>;
+ using IntersectionResult = std::optional<IntersectionLocation>;
+ [[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;
@@ -86,6 +146,8 @@ public:
[[nodiscard]] HalfedgeHandle findEntry(const GlobalPosition2D from, const GlobalPosition2D to) const;
+ void setHeights(const std::span<const GlobalPosition3D> triangleStrip);
+
[[nodiscard]] auto
getExtents() const
{
@@ -102,9 +164,26 @@ protected:
[[nodiscard]] static bool triangleContainsPoint(const GlobalPosition2D, const Triangle<2> &);
[[nodiscard]] bool triangleContainsPoint(const GlobalPosition2D, FaceHandle) const;
+ [[nodiscard]] static bool triangleOverlapsTriangle(const Triangle<2> &, const Triangle<2> &);
+ [[nodiscard]] static bool triangleContainsTriangle(const Triangle<2> &, const Triangle<2> &);
[[nodiscard]] HalfedgeHandle findBoundaryStart() const;
+ [[nodiscard]] RelativePosition3D difference(const HalfedgeHandle) const;
+
+ template<glm::length_t D>
+ [[nodiscard]] static RelativePosition<D>
+ difference(const GlobalPosition<D> a, const GlobalPosition<D> b)
+ {
+ return b - a;
+ }
+
+ [[nodiscard]] RelativeDistance length(const HalfedgeHandle) const;
+ [[nodiscard]] GlobalPosition3D centre(const HalfedgeHandle) const;
void update_vertex_normals_only();
+ void update_vertex_normals_only(VertexIter start);
+
+ using OpenMesh::TriMesh_ArrayKernelT<GeoDataTraits>::split;
+ std::array<FaceHandle, 4> split(FaceHandle);
private:
GlobalPosition3D lowerExtent {}, upperExtent {};
diff --git a/game/network/link.cpp b/game/network/link.cpp
index 122eaf4..248fe7d 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -62,7 +62,7 @@ LinkCurve::intersectRay(const Ray<GlobalPosition3D> & ray) const
const auto & e1p {ends[1].node->pos};
const auto slength = round_frac(length / 2.F, 5.F);
const auto segs = std::round(15.F * slength / std::pow(radius, 0.7F));
- const auto step {glm::vec<2, RelativeDistance> {arc_length(arc), e1p.z - e0p.z} / segs};
+ const auto step {glm::vec<2, RelativeDistance> {arc.length(), e1p.z - e0p.z} / segs};
auto segCount = static_cast<std::size_t>(std::lround(segs)) + 1;
std::vector<GlobalPosition3D> points;
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index 34cbceb..fd07ace 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -95,9 +95,8 @@ round_sleepers(const float v)
return round_frac(v, sleepers);
}
-RailLinkStraight::RailLinkStraight(
- NetworkLinkHolder<RailLinkStraight> & instances, const Node::Ptr & a, const Node::Ptr & b) :
- RailLinkStraight(instances, 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)
{
}
@@ -109,16 +108,15 @@ RailLinkStraight::RailLinkStraight(
{
}
-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(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,
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)),
+ 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)}
diff --git a/game/terrain.cpp b/game/terrain.cpp
index d2c8593..91a228f 100644
--- a/game/terrain.cpp
+++ b/game/terrain.cpp
@@ -30,14 +30,14 @@ Terrain::generateMeshes()
std::vector<Vertex> vertices;
vertices.reserve(geoData->n_vertices());
std::map<GeoData::VertexHandle, size_t> vertexIndex;
- std::transform(geoData->vertices_begin(), geoData->vertices_end(), std::back_inserter(vertices),
+ std::transform(geoData->vertices_sbegin(), geoData->vertices_end(), std::back_inserter(vertices),
[this, &vertexIndex](const GeoData::VertexHandle v) {
vertexIndex.emplace(v, vertexIndex.size());
const auto p = geoData->point(v);
- return Vertex {p, p / 10000, geoData->normal(v)};
+ return Vertex {p, RelativePosition2D(p) / 10000.F, geoData->normal(v)};
});
std::for_each(
- geoData->faces_begin(), geoData->faces_end(), [this, &vertexIndex, &indices](const GeoData::FaceHandle f) {
+ 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](const GeoData::VertexHandle v) {
return vertexIndex[v];