From d6e99a696aa582b81018078b68f6600c8030d643 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Tue, 7 Nov 2023 02:51:42 +0000
Subject: WIP typedefing all the things - headers

---
 lib/geometricPlane.h | 10 +++++----
 lib/location.h       | 12 ++++++-----
 lib/maths.h          | 61 ++++++++++++++++++++++++++--------------------------
 lib/ray.h            | 15 +++++++------
 4 files changed, 53 insertions(+), 45 deletions(-)

(limited to 'lib')

diff --git a/lib/geometricPlane.h b/lib/geometricPlane.h
index dc8df50..c74beff 100644
--- a/lib/geometricPlane.h
+++ b/lib/geometricPlane.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "config/types.h"
 #include <glm/vec3.hpp>
 #include <optional>
 
@@ -9,14 +10,15 @@ class GeometricPlane {
 public:
 	struct DistAndPosition {
 		float dist;
-		glm::vec3 position;
+		Position3D position;
 	};
 	enum class PlaneRelation { Above, Below, On };
 
-	glm::vec3 origin, normal;
+	Position3D origin;
+	Normal3D normal;
 
-	PlaneRelation getRelation(glm::vec3 point) const;
-	std::optional<DistAndPosition> getRayIntersectPosition(const Ray &) const;
+	[[nodiscard]] PlaneRelation getRelation(Position3D point) const;
+	[[nodiscard]] std::optional<DistAndPosition> getRayIntersectPosition(const Ray &) const;
 
 	static bool isIntersect(PlaneRelation a, PlaneRelation b);
 };
diff --git a/lib/location.h b/lib/location.h
index 078f5d3..7f2b44d 100644
--- a/lib/location.h
+++ b/lib/location.h
@@ -1,14 +1,16 @@
 #pragma once
 
+#include "config/types.h"
 #include <glm/mat4x4.hpp>
-#include <glm/vec3.hpp>
 
 class Location {
 public:
-	explicit Location(glm::vec3 pos = {}, glm::vec3 rot = {}) : pos {pos}, rot {rot} { }
+#ifndef __cpp_aggregate_paren_init
+	explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { }
+#endif
 
-	glm::mat4 getTransform() const;
+	[[nodiscard]] glm::mat4 getTransform() const;
 
-	glm::vec3 pos;
-	glm::vec3 rot;
+	Position3D pos;
+	Rotation3D rot;
 };
diff --git a/lib/maths.h b/lib/maths.h
index b95b706..67b2a15 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "config/types.h"
 #include <cmath>
 #include <glm/glm.hpp>
 #include <glm/gtc/constants.hpp>
@@ -9,7 +10,7 @@
 struct Arc : public std::pair<float, float> {
 	using std::pair<float, float>::pair;
 
-	Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p);
+	Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p);
 
 	float
 	operator[](unsigned int i) const
@@ -18,19 +19,19 @@ struct Arc : public std::pair<float, float> {
 	}
 };
 
-constexpr const glm::vec3 origin {0, 0, 0};
-constexpr const glm::vec3 up {0, 0, 1};
-constexpr const glm::vec3 down {0, 0, -1};
-constexpr const glm::vec3 north {0, 1, 0};
-constexpr const glm::vec3 south {0, -1, 0};
-constexpr const glm::vec3 east {1, 0, 0};
-constexpr const glm::vec3 west {-1, 0, 0};
+constexpr const Position3D origin {0, 0, 0};
+constexpr const Position3D up {0, 0, 1};
+constexpr const Position3D down {0, 0, -1};
+constexpr const Position3D north {0, 1, 0};
+constexpr const Position3D south {0, -1, 0};
+constexpr const Position3D east {1, 0, 0};
+constexpr const Position3D west {-1, 0, 0};
 constexpr auto half_pi {glm::half_pi<float>()};
 constexpr auto quarter_pi {half_pi / 2};
 constexpr auto pi {glm::pi<float>()};
 constexpr auto two_pi {glm::two_pi<float>()};
 
-glm::mat4 flat_orientation(const glm::vec3 & diff);
+glm::mat4 flat_orientation(const Rotation3D & diff);
 
 // C++ wrapper for C's sincosf, but with references, not pointers
 inline auto
@@ -39,10 +40,10 @@ sincosf(float a, float & s, float & c)
 	return sincosf(a, &s, &c);
 }
 
-inline glm::vec2
+inline Rotation2D
 sincosf(float a)
 {
-	glm::vec2 sc;
+	Rotation2D sc;
 	sincosf(a, sc.x, sc.y);
 	return sc;
 }
@@ -51,11 +52,11 @@ glm::mat2 rotate_flat(float);
 glm::mat4 rotate_roll(float);
 glm::mat4 rotate_yaw(float);
 glm::mat4 rotate_pitch(float);
-glm::mat4 rotate_yp(glm::vec2);
-glm::mat4 rotate_ypr(glm::vec3);
+glm::mat4 rotate_yp(Rotation2D);
+glm::mat4 rotate_ypr(Rotation3D);
 
-float vector_yaw(const glm::vec3 & diff);
-float vector_pitch(const glm::vec3 & diff);
+float vector_yaw(const Direction3D & diff);
+float vector_pitch(const Direction3D & diff);
 
 float round_frac(const float & v, const float & frac);
 
@@ -87,26 +88,26 @@ perspective_divide(glm::vec<4, T, Q> v)
 	return v / v.w;
 }
 
-constexpr inline glm::vec2
-operator!(const glm::vec3 & v)
+constexpr inline Position2D
+operator!(const Position3D & v)
 {
 	return {v.x, v.y};
 }
 
-constexpr inline glm::vec3
-operator^(const glm::vec2 & v, float z)
+constexpr inline Position3D
+operator^(const Position2D & v, float z)
 {
 	return {v.x, v.y, z};
 }
 
 constexpr inline glm::vec4
-operator^(const glm::vec3 & v, float w)
+operator^(const Position3D & v, float w)
 {
 	return {v.x, v.y, v.z, w};
 }
 
-constexpr inline glm::vec3
-operator!(const glm::vec2 & v)
+constexpr inline Position3D
+operator!(const Position2D & v)
 {
 	return v ^ 0.F;
 }
@@ -125,15 +126,15 @@ operator||(const glm::vec<L, T, Q> v1, const T v2)
 	return {v1, v2};
 }
 
-inline glm::vec3
-operator%(const glm::vec3 & p, const glm::mat4 & mutation)
+inline Position3D
+operator%(const Position3D & p, const glm::mat4 & mutation)
 {
 	const auto p2 = mutation * (p ^ 1);
 	return p2 / p2.w;
 }
 
-inline glm::vec3
-operator%=(glm::vec3 & p, const glm::mat4 & mutation)
+inline Position3D
+operator%=(Position3D & p, const glm::mat4 & mutation)
 {
 	return p = p % mutation;
 }
@@ -146,10 +147,10 @@ arc_length(const Arc & arc)
 
 float normalize(float ang);
 
-std::pair<glm::vec2, bool> find_arc_centre(glm::vec2 start, float entrys, glm::vec2 end, float entrye);
-std::pair<glm::vec2, bool> find_arc_centre(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd);
-std::pair<float, float> find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye);
-float find_arcs_radius(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd);
+std::pair<Position2D, bool> find_arc_centre(Position2D start, float entrys, Position2D end, float entrye);
+std::pair<Position2D, bool> find_arc_centre(Position2D start, Position2D ad, Position2D end, Position2D bd);
+std::pair<float, float> find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye);
+float find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd);
 
 template<typename T>
 auto
diff --git a/lib/ray.h b/lib/ray.h
index 9bf47af..bc70c74 100644
--- a/lib/ray.h
+++ b/lib/ray.h
@@ -1,17 +1,20 @@
 #pragma once
 
+#include "config/types.h"
 #include <glm/glm.hpp>
 #include <span>
 
 class Ray {
 public:
-	Ray(glm::vec3 start, glm::vec3 direction) : start {start}, direction {direction} { }
+#ifndef __cpp_aggregate_paren_init
+	Ray(Position3D start, Direction3D direction) : start {start}, direction {direction} { }
+#endif
 
-	static Ray fromPoints(glm::vec3, glm::vec3);
+	static Ray fromPoints(Position3D, Position3D);
 
-	glm::vec3 start;
-	glm::vec3 direction;
+	Position3D start;
+	Direction3D direction;
 
-	float distanceToLine(const glm::vec3 & a, const glm::vec3 & b) const;
-	bool passesCloseToEdges(const std::span<const glm::vec3> positions, float distance) const;
+	[[nodiscard]] float distanceToLine(const Position3D & a, const Position3D & b) const;
+	[[nodiscard]] bool passesCloseToEdges(const std::span<const Position3D> positions, float distance) const;
 };
-- 
cgit v1.2.3


From 9c2c3f71065c94a18c02440111b6ff8ca977b90e Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Thu, 9 Nov 2023 00:40:40 +0000
Subject: WIP typedefing all the things - sources

---
 assetFactory/cuboid.cpp       |  2 +-
 assetFactory/cylinder.cpp     |  6 +++---
 assetFactory/plane.cpp        |  2 +-
 assetFactory/shape.cpp        |  4 +---
 game/network/link.cpp         | 14 +++++++-------
 game/network/network.cpp      | 18 +++++++++---------
 game/network/rail.cpp         | 30 +++++++++++++++---------------
 game/vehicles/railVehicle.cpp | 12 ++++++------
 game/vehicles/train.cpp       |  2 +-
 gfx/gl/bufferedLocation.cpp   | 12 ++++++------
 gfx/gl/camera.cpp             | 11 ++++++-----
 gfx/gl/sceneRenderer.cpp      |  7 +++----
 gfx/gl/sceneShader.cpp        | 14 +++++++-------
 gfx/gl/shadowMapper.cpp       | 10 +++++-----
 gfx/gl/uiShader.cpp           |  2 +-
 gfx/models/texture.cpp        |  6 +++---
 lib/geometricPlane.cpp        |  4 ++--
 lib/maths.cpp                 | 40 ++++++++++++++++++++--------------------
 lib/ray.cpp                   |  8 ++++----
 test/test-assetFactory.cpp    |  2 +-
 test/testRenderOutput.cpp     |  2 +-
 ui/builders/straight.cpp      |  2 +-
 ui/gameMainSelector.cpp       |  9 +++++----
 ui/gameMainWindow.cpp         |  4 ++--
 ui/manualCameraController.cpp |  2 +-
 25 files changed, 112 insertions(+), 113 deletions(-)

(limited to 'lib')

diff --git a/assetFactory/cuboid.cpp b/assetFactory/cuboid.cpp
index a8ddcd9..cfb6cfb 100644
--- a/assetFactory/cuboid.cpp
+++ b/assetFactory/cuboid.cpp
@@ -4,7 +4,7 @@
 Cuboid::CreatedFaces
 Cuboid::createMesh(ModelFactoryMesh & mesh, float) const
 {
-	static constexpr std::array<glm::vec3, 8> VERTICES {{
+	static constexpr std::array<Position3D, 8> VERTICES {{
 			// bottom
 			{n, n, z},
 			{n, y, z},
diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp
index 7d22e36..ed034fd 100644
--- a/assetFactory/cylinder.cpp
+++ b/assetFactory/cylinder.cpp
@@ -9,8 +9,8 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const
 	const auto step = two_pi / static_cast<float>(P);
 
 	// Generate 2D circumference points
-	std::vector<glm::vec2> circumference(P);
-	std::generate(circumference.begin(), circumference.end(), [a = 0.f, step]() mutable {
+	std::vector<Position2D> circumference(P);
+	std::generate(circumference.begin(), circumference.end(), [a = 0.F, step]() mutable {
 		return sincosf(a += step) * .5F;
 	});
 
@@ -19,7 +19,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const
 		// Generate bottom face vertices
 		std::vector<OpenMesh::VertexHandle> bottom(P);
 		std::transform(circumference.begin(), circumference.end(), bottom.begin(), [&mesh](const auto & xy) {
-			return mesh.add_vertex(xy ^ 0.f);
+			return mesh.add_vertex(xy ^ 0.F);
 		});
 		surface.insert(mesh.add_namedFace("bottom", bottom));
 	}
diff --git a/assetFactory/plane.cpp b/assetFactory/plane.cpp
index c6e1b5a..28fb690 100644
--- a/assetFactory/plane.cpp
+++ b/assetFactory/plane.cpp
@@ -4,7 +4,7 @@
 Plane::CreatedFaces
 Plane::createMesh(ModelFactoryMesh & mesh, float) const
 {
-	static constexpr std::array<glm::vec3, 4> VERTICES {{
+	static constexpr std::array<Position3D, 4> VERTICES {{
 			{n, n, z},
 			{y, n, z},
 			{y, y, z},
diff --git a/assetFactory/shape.cpp b/assetFactory/shape.cpp
index 1bfbdbb..0f83ee5 100644
--- a/assetFactory/shape.cpp
+++ b/assetFactory/shape.cpp
@@ -1,11 +1,9 @@
 #include "shape.h"
-#include "gfx/models/vertex.h"
-#include "maths.h"
 #include "modelFactoryMesh.h"
 #include "shape.h"
 
 std::vector<OpenMesh::VertexHandle>
-Shape::addToMesh(ModelFactoryMesh & mesh, const std::span<const glm::vec3> vertices)
+Shape::addToMesh(ModelFactoryMesh & mesh, const std::span<const Position3D> vertices)
 {
 	std::vector<OpenMesh::VertexHandle> vhs;
 	std::transform(vertices.begin(), vertices.end(), std::back_inserter(vhs), [&mesh](const auto & p) {
diff --git a/game/network/link.cpp b/game/network/link.cpp
index bb27a52..498afe4 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -8,10 +8,10 @@
 
 Link::Link(End a, End b, float l) : ends {{std::move(a), std::move(b)}}, length {l} { }
 
-LinkCurve::LinkCurve(glm::vec3 c, float r, Arc a) : centreBase {c}, radius {r}, arc {std::move(a)} { }
+LinkCurve::LinkCurve(Position3D c, float r, Arc a) : centreBase {c}, radius {r}, arc {std::move(a)} { }
 
 bool
-operator<(const glm::vec3 & a, const glm::vec3 & b)
+operator<(const Position3D & a, const Position3D & b)
 {
 	// NOLINTNEXTLINE(hicpp-use-nullptr,modernize-use-nullptr)
 	return std::tie(a.x, a.y, a.z) < std::tie(b.x, b.y, b.z);
@@ -48,7 +48,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const
 	const auto ang {as.first + ((as.second - as.first) * frac)};
 	const auto relPos {!sincosf(ang) * radius};
 	const auto relClimb {vehiclePositionOffset()
-			+ glm::vec3 {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}};
+			+ Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}};
 	const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})};
 	return Location {relPos + relClimb + centreBase, {pitch, normalize(ang + dirOffset[start]), 0}};
 }
@@ -60,14 +60,14 @@ LinkCurve::intersectRay(const Ray & 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::vec3 {arc_length(arc), e1p.z - e0p.z, slength} / segs};
+	const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength} / segs};
 	const auto trans {glm::translate(centreBase)};
 
 	auto segCount = static_cast<std::size_t>(std::lround(segs)) + 1;
-	std::vector<glm::vec3> points;
+	std::vector<Position3D> points;
 	points.reserve(segCount);
-	for (glm::vec3 swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) {
-		const auto t {trans * glm::rotate(half_pi - swing.x, up) * glm::translate(glm::vec3 {radius, 0.F, swing.y})};
+	for (Position3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) {
+		const auto t {trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})};
 		points.emplace_back(t * glm::vec4 {0, 0, 0, 1});
 	}
 	return ray.passesCloseToEdges(points, 1.F);
diff --git a/game/network/network.cpp b/game/network/network.cpp
index 083b08e..d18345c 100644
--- a/game/network/network.cpp
+++ b/game/network/network.cpp
@@ -14,13 +14,13 @@
 Network::Network(const std::string & tn) : texture {Texture::cachedTexture.get(tn)} { }
 
 Node::Ptr
-Network::nodeAt(glm::vec3 pos)
+Network::nodeAt(Position3D pos)
 {
 	return newNodeAt(pos).first;
 }
 
 Network::NodeInsertion
-Network::newNodeAt(glm::vec3 pos)
+Network::newNodeAt(Position3D pos)
 {
 	if (auto [n, i] = candidateNodeAt(pos); i == NodeIs::NotInNetwork) {
 		return {*nodes.insert(std::move(n)).first, i};
@@ -31,7 +31,7 @@ Network::newNodeAt(glm::vec3 pos)
 }
 
 Node::Ptr
-Network::findNodeAt(glm::vec3 pos) const
+Network::findNodeAt(Position3D pos) const
 {
 	if (const auto n = nodes.find(pos); n != nodes.end()) {
 		return *n;
@@ -40,7 +40,7 @@ Network::findNodeAt(glm::vec3 pos) const
 }
 
 Network::NodeInsertion
-Network::candidateNodeAt(glm::vec3 pos) const
+Network::candidateNodeAt(Position3D pos) const
 {
 	if (const auto n = nodes.find(pos); n != nodes.end()) {
 		return {*n, NodeIs::InNetwork};
@@ -54,7 +54,7 @@ Network::intersectRayNodes(const Ray & ray) const
 	// Click within 2m of a node
 	if (const auto node = std::find_if(nodes.begin(), nodes.end(),
 				[&ray](const Node::Ptr & node) {
-					glm::vec3 ipos, inorm;
+					Position3D ipos, inorm;
 					return glm::intersectRaySphere(ray.start, ray.direction, node->pos, 2.F, ipos, inorm);
 				});
 			node != nodes.end()) {
@@ -79,7 +79,7 @@ Network::joinLinks(const Link::Ptr & l, const Link::Ptr & ol)
 }
 
 Link::Nexts
-Network::routeFromTo(const Link::End & start, glm::vec3 dest) const
+Network::routeFromTo(const Link::End & start, Position3D dest) const
 {
 	auto destNode {findNodeAt(dest)};
 	if (!destNode) {
@@ -95,7 +95,7 @@ Network::routeFromTo(const Link::End & end, const Node::Ptr & dest) const
 }
 
 GenCurveDef
-Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float startDir)
+Network::genCurveDef(const Position3D & start, const Position3D & end, float startDir)
 {
 	const auto diff {end - start};
 	const auto vy {vector_yaw(diff)};
@@ -111,11 +111,11 @@ Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float start
 }
 
 std::pair<GenCurveDef, GenCurveDef>
-Network::genCurveDef(const glm::vec3 & start, const glm::vec3 & end, float startDir, float endDir)
+Network::genCurveDef(const Position3D & start, const Position3D & end, float startDir, float endDir)
 {
 	startDir += pi;
 	endDir += pi;
-	const glm::vec2 flatStart {!start}, flatEnd {!end};
+	const Position2D flatStart {!start}, flatEnd {!end};
 	auto midheight = [&](auto mid) {
 		const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid);
 		return start.z + ((end.z - start.z) * (sm / (sm + em)));
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index 5a4f1e1..f46504b 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -18,7 +18,7 @@
 template class NetworkOf<RailLink>;
 
 constexpr auto RAIL_CROSSSECTION_VERTICES {5U};
-constexpr glm::vec3 RAIL_HEIGHT {0, 0, .25F};
+constexpr Size3D RAIL_HEIGHT {0, 0, .25F};
 
 RailLinks::RailLinks() : NetworkOf<RailLink> {"rails.jpg"} { }
 
@@ -28,7 +28,7 @@ RailLinks::tick(TickDuration)
 }
 
 std::shared_ptr<RailLink>
-RailLinks::addLinksBetween(glm::vec3 start, glm::vec3 end)
+RailLinks::addLinksBetween(Position3D start, Position3D end)
 {
 	auto node1ins = newNodeAt(start), node2ins = newNodeAt(end);
 	if (node1ins.second == NodeIs::NotInNetwork && node2ins.second == NodeIs::NotInNetwork) {
@@ -45,7 +45,7 @@ RailLinks::addLinksBetween(glm::vec3 start, glm::vec3 end)
 	if (dir == vector_yaw(end - start)) {
 		return addLink<RailLinkStraight>(start, end);
 	}
-	const glm::vec2 flatStart {!start}, flatEnd {!end};
+	const Position2D flatStart {!start}, flatEnd {!end};
 	if (node2ins.second == NodeIs::InNetwork) {
 		auto midheight = [&](auto mid) {
 			const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid);
@@ -100,7 +100,7 @@ RailLink::render(const SceneShader &) const
 	mesh->Draw();
 }
 
-constexpr const std::array<std::pair<glm::vec3, float>, RAIL_CROSSSECTION_VERTICES> railCrossSection {{
+constexpr const std::array<std::pair<Position3D, float>, RAIL_CROSSSECTION_VERTICES> railCrossSection {{
 		//   ___________
 		// _/           \_
 		//  left to right
@@ -122,7 +122,7 @@ RailLinkStraight::RailLinkStraight(const Node::Ptr & a, const Node::Ptr & b) : R
 {
 }
 
-RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const glm::vec3 & diff) :
+RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D & diff) :
 	Link({std::move(a), vector_yaw(diff)}, {std::move(b), vector_yaw(-diff)}, glm::length(diff))
 {
 	if (glGenVertexArrays) {
@@ -133,20 +133,20 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const glm::vec3 & d
 		for (auto ei : {1U, 0U}) {
 			const auto trans {glm::translate(ends[ei].node->pos) * e};
 			for (const auto & rcs : railCrossSection) {
-				const glm::vec3 m {(trans * glm::vec4 {rcs.first, 1})};
-				vertices.emplace_back(m, glm::vec2 {rcs.second, len * static_cast<float>(ei)}, up);
+				const Position3D m {(trans * glm::vec4 {rcs.first, 1})};
+				vertices.emplace_back(m, Position2D {rcs.second, len * static_cast<float>(ei)}, up);
 			}
 		}
 		mesh = defaultMesh(vertices);
 	}
 }
 
-RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec2 c) :
+RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) :
 	RailLinkCurve(a, b, c ^ a->pos.z, {!c, a->pos, b->pos})
 {
 }
 
-RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec3 c, const Arc arc) :
+RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3D c, const Arc arc) :
 	Link({a, normalize(arc.first + half_pi)}, {b, normalize(arc.second - half_pi)},
 			(glm::length(a->pos - c)) * arc_length(arc)),
 	LinkCurve {c, glm::length(ends[0].node->pos - c), arc}
@@ -156,25 +156,25 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, glm::vec3
 		const auto & e1p {ends[1].node->pos};
 		const auto slength = round_sleepers(length / 2.F);
 		const auto segs = std::round(15.F * slength / std::pow(radius, 0.7F));
-		const auto step {glm::vec3 {arc_length(arc), e1p.z - e0p.z, slength} / segs};
+		const auto step {Position3D {arc_length(arc), e1p.z - e0p.z, slength} / segs};
 		const auto trans {glm::translate(centreBase)};
 
 		auto segCount = static_cast<std::size_t>(std::lround(segs)) + 1;
 		std::vector<Vertex> vertices;
 		vertices.reserve(segCount * railCrossSection.size());
-		for (glm::vec3 swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) {
+		for (Position3D swing = {arc.first, centreBase.z - e0p.z, 0.F}; segCount; swing += step, --segCount) {
 			const auto t {
-					trans * glm::rotate(half_pi - swing.x, up) * glm::translate(glm::vec3 {radius, 0.F, swing.y})};
+					trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})};
 			for (const auto & rcs : railCrossSection) {
-				const glm::vec3 m {(t * glm::vec4 {rcs.first, 1})};
-				vertices.emplace_back(m, glm::vec2 {rcs.second, swing.z}, up);
+				const Position3D m {(t * glm::vec4 {rcs.first, 1})};
+				vertices.emplace_back(m, Position2D {rcs.second, swing.z}, up);
 			}
 		}
 		mesh = defaultMesh(vertices);
 	}
 }
 
-glm::vec3
+Position3D
 RailLink::vehiclePositionOffset() const
 {
 	return RAIL_HEIGHT;
diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index 2d820b6..fc43995 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -14,8 +14,8 @@
 RailVehicle::RailVehicle(RailVehicleClassPtr rvc) :
 	RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, location {&LV::body, *this},
 	bogies {{
-			{&LV::front, *this, glm::vec3 {0, rvClass->wheelBase / 2.F, 0}},
-			{&LV::back, *this, glm::vec3 {0, -rvClass->wheelBase / 2.F, 0}},
+			{&LV::front, *this, Position3D {0, rvClass->wheelBase / 2.F, 0}},
+			{&LV::back, *this, Position3D {0, -rvClass->wheelBase / 2.F, 0}},
 	}}
 {
 }
@@ -32,13 +32,13 @@ RailVehicle::move(const Train * t, float & trailBy)
 }
 
 bool
-RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance) const
+RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const
 {
 	constexpr const auto X = 1.35F;
 	const auto Y = this->rvClass->length / 2.F;
 	constexpr const auto Z = 3.9F;
 	const auto moveBy = location.getTransform();
-	const std::array<glm::vec3, 8> cornerVertices {{
+	const std::array<Position3D, 8> cornerVertices {{
 			moveBy * glm::vec4 {-X, Y, 0, 1}, //  LFB
 			moveBy * glm::vec4 {X, Y, 0, 1}, //   RFB
 			moveBy * glm::vec4 {-X, Y, Z, 1}, //  LFT
@@ -48,7 +48,7 @@ RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance
 			moveBy * glm::vec4 {-X, -Y, Z, 1}, // LBT
 			moveBy * glm::vec4 {X, -Y, Z, 1}, //  RBT
 	}};
-	static constexpr const std::array<glm::uvec3, 10> triangles {{
+	static constexpr const std::array<glm::vec<3, uint8_t>, 10> triangles {{
 			// Front
 			{0, 1, 2},
 			{1, 2, 3},
@@ -66,7 +66,7 @@ RailVehicle::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance
 			{3, 6, 7},
 	}};
 	return std::any_of(
-			triangles.begin(), triangles.end(), [&cornerVertices, &ray, &baryPos, &distance](const glm::uvec3 idx) {
+			triangles.begin(), triangles.end(), [&cornerVertices, &ray, &baryPos, &distance](const auto & idx) {
 				return glm::intersectRayTriangle(ray.start, ray.direction, cornerVertices[idx[0]],
 						cornerVertices[idx[1]], cornerVertices[idx[2]], *baryPos, *distance);
 			});
diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp
index 6f3b036..4aa24dc 100644
--- a/game/vehicles/train.cpp
+++ b/game/vehicles/train.cpp
@@ -20,7 +20,7 @@ Train::getBogiePosition(float linkDist, float dist) const
 }
 
 bool
-Train::intersectRay(const Ray & ray, glm::vec2 * baryPos, float * distance) const
+Train::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const
 {
 	return applyOne(&RailVehicle::intersectRay, ray, baryPos, distance) != end();
 }
diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp
index eb3dac3..62cadef 100644
--- a/gfx/gl/bufferedLocation.cpp
+++ b/gfx/gl/bufferedLocation.cpp
@@ -3,7 +3,7 @@
 #include "maths.h"
 #include <glm/gtx/transform.hpp>
 
-BufferedLocation::BufferedLocation(glm::vec3 p, glm::vec3 r) : BufferedLocation {Location {p, r}} { }
+BufferedLocation::BufferedLocation(Position3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { }
 
 BufferedLocation::BufferedLocation(const Location & l) : loc {l} { }
 
@@ -20,20 +20,20 @@ BufferedLocation::operator=(const Location & l)
 	return *this;
 }
 
-glm::vec3
+Position3D
 BufferedLocation::position() const
 {
 	return loc.pos;
 }
 
-glm::vec3
+Position3D
 BufferedLocation::rotation() const
 {
 	return loc.rot;
 }
 
 void
-BufferedLocation::setPosition(glm::vec3 p, bool update)
+BufferedLocation::setPosition(Position3D p, bool update)
 {
 	loc.pos = p;
 	if (update) {
@@ -42,7 +42,7 @@ BufferedLocation::setPosition(glm::vec3 p, bool update)
 }
 
 void
-BufferedLocation::setRotation(glm::vec3 r, bool update)
+BufferedLocation::setRotation(Position3D r, bool update)
 {
 	loc.rot = r;
 	if (update) {
@@ -51,7 +51,7 @@ BufferedLocation::setRotation(glm::vec3 r, bool update)
 }
 
 void
-BufferedLocation::setLocation(glm::vec3 p, glm::vec3 r)
+BufferedLocation::setLocation(Position3D p, Rotation3D r)
 {
 	loc.pos = p;
 	loc.rot = r;
diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp
index 80feab4..6a0359c 100644
--- a/gfx/gl/camera.cpp
+++ b/gfx/gl/camera.cpp
@@ -2,6 +2,7 @@
 #include <collections.h>
 #include <glm/gtx/intersect.hpp> // IWYU pragma: keep
 #include <glm/gtx/transform.hpp> // IWYU pragma: keep
+#include <math.h>
 #include <maths.h>
 #include <ray.h>
 
@@ -28,8 +29,8 @@ Camera::updateView()
 	inverseViewProjection = glm::inverse(viewProjection);
 }
 
-glm::vec3
-Camera::upFromForward(const glm::vec3 & forward)
+Direction3D
+Camera::upFromForward(const Direction3D & forward)
 {
 	const auto right = glm::cross(forward, ::down);
 	return glm::cross(forward, right);
@@ -38,11 +39,11 @@ Camera::upFromForward(const glm::vec3 & forward)
 std::array<glm::vec4, 4>
 Camera::extentsAtDist(const float dist) const
 {
-	const auto clampToSeaFloor = [this, dist](const glm::vec3 & target) {
+	const auto clampToSeaFloor = [this, dist](const Position3D & target) {
 		if (target.z < -1.5F) {
 			const auto vec = glm::normalize(target - position);
-			constexpr glm::vec3 seafloor {0, 0, -1.5F};
-			float outdist;
+			constexpr Position3D seafloor {0, 0, -1.5F};
+			float outdist {};
 			if (glm::intersectRayPlane(position, vec, seafloor, ::up, outdist)) {
 				return (vec * outdist + position) ^ outdist;
 			}
diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp
index 218cf6d..6965175 100644
--- a/gfx/gl/sceneRenderer.cpp
+++ b/gfx/gl/sceneRenderer.cpp
@@ -97,7 +97,7 @@ SceneRenderer::render(const SceneProvider & scene) const
 }
 
 void
-SceneRenderer::setAmbientLight(const glm::vec3 & colour) const
+SceneRenderer::setAmbientLight(const RGB & colour) const
 {
 	glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
 	glClearColor(colour.r, colour.g, colour.b, 1.0F);
@@ -105,8 +105,7 @@ SceneRenderer::setAmbientLight(const glm::vec3 & colour) const
 }
 
 void
-SceneRenderer::setDirectionalLight(
-		const glm::vec3 & colour, const glm::vec3 & direction, const SceneProvider & scene) const
+SceneRenderer::setDirectionalLight(const RGB & colour, const Direction3D & direction, const SceneProvider & scene) const
 {
 	if (colour.r > 0 || colour.g > 0 || colour.b > 0) {
 		const auto lvp = shadowMapper.update(scene, direction, camera);
@@ -135,7 +134,7 @@ SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() :
 }
 
 void
-SceneRenderer::DirectionalLightProgram::setDirectionalLight(const glm::vec3 & c, const glm::vec3 & d,
+SceneRenderer::DirectionalLightProgram::setDirectionalLight(const RGB & c, const Direction3D & d,
 		const std::span<const glm::mat4x4> lvp, const std::span<const glm::vec4> shadowMapRegions,
 		std::size_t maps) const
 {
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index 1354611..04b6d9e 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -81,25 +81,25 @@ void
 SceneShader::WaterProgram::use(float waveCycle) const
 {
 	Program::use();
-	glm::vec3 waves {waveCycle, 0.F, 0.F};
+	Position3D waves {waveCycle, 0.F, 0.F};
 	glUniform3fv(waveLoc, 1, glm::value_ptr(waves));
 }
 
 SceneShader::PointLightShader::PointLightShader() :
 	SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"}
 {
-	VertexArrayObject {va}.addAttribs<glm::vec3>(b);
+	VertexArrayObject {va}.addAttribs<Position3D>(b);
 }
 
 void
-SceneShader::PointLightShader::add(const glm::vec3 & position, const glm::vec3 & colour, const float kq) const
+SceneShader::PointLightShader::add(const Position3D & position, const RGB & colour, const float kq) const
 {
 	Program::use();
 	glBindVertexArray(va);
 	glBindBuffer(GL_ARRAY_BUFFER, b);
 	glUniform3fv(colourLoc, 1, glm::value_ptr(colour));
 	glUniform1f(kqLoc, kq);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(Position3D), glm::value_ptr(position), GL_DYNAMIC_DRAW);
 	glDrawArrays(GL_POINTS, 0, 1);
 }
 
@@ -107,12 +107,12 @@ SceneShader::SpotLightShader::SpotLightShader() :
 	SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, directionLoc {*this, "v_direction"},
 	colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"}
 {
-	using v3pair = std::pair<glm::vec3, glm::vec3>;
+	using v3pair = std::pair<Position3D, Direction3D>;
 	VertexArrayObject {va}.addAttribs<v3pair, &v3pair::first, &v3pair::second>(b);
 }
 
 void
-SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 & direction, const glm::vec3 & colour,
+SceneShader::SpotLightShader::add(const Position3D & position, const Direction3D & direction, const RGB & colour,
 		const float kq, const float arc) const
 {
 	Program::use();
@@ -122,6 +122,6 @@ SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 &
 	glUniform3fv(directionLoc, 1, glm::value_ptr(direction));
 	glUniform1f(kqLoc, kq);
 	glUniform1f(arcLoc, arc);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(Position3D), glm::value_ptr(position), GL_DYNAMIC_DRAW);
 	glDrawArrays(GL_POINTS, 0, 1);
 }
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 58f65c4..aea5af3 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -104,14 +104,14 @@ struct DefinitionsInserter {
 	ShadowMapper::Definitions & out;
 };
 
-std::vector<std::array<glm::vec3, 4>>
+std::vector<std::array<Position3D, 4>>
 ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightView)
 {
-	std::vector<std::array<glm::vec3, 4>> bandViewExtents;
+	std::vector<std::array<Position3D, 4>> bandViewExtents;
 	for (const auto dist : shadowBands) {
 		const auto extents = camera.extentsAtDist(dist);
-		bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> glm::vec3 {
-			return lightView * glm::vec4(glm::vec3 {e}, 1);
+		bandViewExtents.emplace_back(extents * [&lightView](const auto & e) -> Position3D {
+			return lightView * glm::vec4(Position3D {e}, 1);
 		});
 		if (std::none_of(extents.begin(), extents.end(), [targetDist = dist * 0.99F](const glm::vec4 & e) {
 				return e.w > targetDist;
@@ -123,7 +123,7 @@ ShadowMapper::getBandViewExtents(const Camera & camera, const glm::mat4 & lightV
 }
 
 ShadowMapper::Definitions
-ShadowMapper::update(const SceneProvider & scene, const glm::vec3 & dir, const Camera & camera) const
+ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const Camera & camera) const
 {
 	glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
 	glClear(GL_DEPTH_BUFFER_BIT);
diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp
index 0b47211..dc4f4dc 100644
--- a/gfx/gl/uiShader.cpp
+++ b/gfx/gl/uiShader.cpp
@@ -23,7 +23,7 @@ UIShader::UIShader(size_t width, size_t height) :
 UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { }
 
 void
-UIShader::TextProgram::use(const glm::vec3 & colour) const
+UIShader::TextProgram::use(const RGB & colour) const
 {
 	Program::use();
 	glUniform3fv(colorLoc, 1, glm::value_ptr(colour));
diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp
index f60d158..1685d34 100644
--- a/gfx/models/texture.cpp
+++ b/gfx/models/texture.cpp
@@ -61,10 +61,10 @@ Texture::bind(GLenum unit) const
 	glBindTexture(type, m_texture);
 }
 
-glm::ivec2
+TextureAbsCoord
 Texture::getSize(const glTexture & texture)
 {
-	glm::ivec2 size;
+	TextureAbsCoord size;
 	glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_WIDTH, &size.x);
 	glGetTextureLevelParameteriv(texture, 0, GL_TEXTURE_HEIGHT, &size.y);
 	return size;
@@ -137,7 +137,7 @@ TextureAtlas::bind(GLenum unit) const
 }
 
 GLuint
-TextureAtlas::add(glm::ivec2 position, glm::ivec2 size, void * data, TextureOptions to)
+TextureAtlas::add(TextureAbsCoord position, TextureAbsCoord size, void * data, TextureOptions to)
 {
 	glTextureSubImage2D(m_texture, 0, position.x, position.y, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, data);
 
diff --git a/lib/geometricPlane.cpp b/lib/geometricPlane.cpp
index ea4f02d..567f98a 100644
--- a/lib/geometricPlane.cpp
+++ b/lib/geometricPlane.cpp
@@ -4,10 +4,10 @@
 #include <glm/gtx/intersect.hpp>
 
 GeometricPlane::PlaneRelation
-GeometricPlane::getRelation(glm::vec3 p) const
+GeometricPlane::getRelation(Position3D p) const
 {
 	const auto d = glm::dot(normal, p - origin);
-	return d < 0.f ? PlaneRelation::Below : d > 0.f ? PlaneRelation::Above : PlaneRelation::On;
+	return d < 0.F ? PlaneRelation::Below : d > 0.F ? PlaneRelation::Above : PlaneRelation::On;
 }
 
 bool
diff --git a/lib/maths.cpp b/lib/maths.cpp
index 7594b59..5430ef6 100644
--- a/lib/maths.cpp
+++ b/lib/maths.cpp
@@ -6,7 +6,7 @@
 #include <stdexcept>
 
 glm::mat4
-flat_orientation(const glm::vec3 & diff)
+flat_orientation(const Direction3D & diff)
 {
 	static const auto oneeighty {glm::rotate(pi, up)};
 	const auto flatdiff {glm::normalize(!!diff)};
@@ -16,17 +16,17 @@ flat_orientation(const glm::vec3 & diff)
 }
 
 // Helper to lookup into a matrix given an xy vector coordinate
-template<typename M>
+template<typename M, typename I>
 inline auto &
-operator^(M & m, glm::ivec2 xy)
+operator^(M & m, glm::vec<2, I> xy)
 {
 	return m[xy.x][xy.y];
 }
 
 // Create a matrix for the angle, given the targets into the matrix
-template<typename M>
+template<typename M, typename I>
 inline auto
-rotation(typename M::value_type a, glm::ivec2 c1, glm::ivec2 s1, glm::ivec2 c2, glm::ivec2 ms2)
+rotation(typename M::value_type a, glm::vec<2, I> c1, glm::vec<2, I> s1, glm::vec<2, I> c2, glm::vec<2, I> ms2)
 {
 	M m(1);
 	sincosf(a, m ^ s1, m ^ c1);
@@ -39,51 +39,51 @@ rotation(typename M::value_type a, glm::ivec2 c1, glm::ivec2 s1, glm::ivec2 c2,
 glm::mat2
 rotate_flat(float a)
 {
-	return rotation<glm::mat2>(a, {0, 0}, {0, 1}, {1, 1}, {1, 0});
+	return rotation<glm::mat2, glm::length_t>(a, {0, 0}, {0, 1}, {1, 1}, {1, 0});
 }
 
 // Create a yaw transformation matrix
 glm::mat4
 rotate_yaw(float a)
 {
-	return rotation<glm::mat4>(a, {0, 0}, {1, 0}, {1, 1}, {0, 1});
+	return rotation<glm::mat4, glm::length_t>(a, {0, 0}, {1, 0}, {1, 1}, {0, 1});
 }
 
 // Create a roll transformation matrix
 glm::mat4
 rotate_roll(float a)
 {
-	return rotation<glm::mat4>(a, {0, 0}, {2, 0}, {2, 2}, {0, 2});
+	return rotation<glm::mat4, glm::length_t>(a, {0, 0}, {2, 0}, {2, 2}, {0, 2});
 }
 
 // Create a pitch transformation matrix
 glm::mat4
 rotate_pitch(float a)
 {
-	return rotation<glm::mat4>(a, {1, 1}, {1, 2}, {2, 2}, {2, 1});
+	return rotation<glm::mat4, glm::length_t>(a, {1, 1}, {1, 2}, {2, 2}, {2, 1});
 }
 
 // Create a combined yaw, pitch, roll transformation matrix
 glm::mat4
-rotate_ypr(glm::vec3 a)
+rotate_ypr(Rotation3D a)
 {
 	return rotate_yaw(a.y) * rotate_pitch(a.x) * rotate_roll(a.z);
 }
 
 glm::mat4
-rotate_yp(glm::vec2 a)
+rotate_yp(Rotation2D a)
 {
 	return rotate_yaw(a.y) * rotate_pitch(a.x);
 }
 
 float
-vector_yaw(const glm::vec3 & diff)
+vector_yaw(const Direction3D & diff)
 {
 	return std::atan2(diff.x, diff.y);
 }
 
 float
-vector_pitch(const glm::vec3 & diff)
+vector_pitch(const Direction3D & diff)
 {
 	return std::atan(diff.z);
 }
@@ -106,7 +106,7 @@ normalize(float ang)
 	return ang;
 }
 
-Arc::Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p) :
+Arc::Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p) :
 	Arc([&]() -> Arc {
 		const auto diffa = e0p - centre3;
 		const auto diffb = e1p - centre3;
@@ -120,8 +120,8 @@ Arc::Arc(const glm::vec3 & centre3, const glm::vec3 & e0p, const glm::vec3 & e1p
 {
 }
 
-std::pair<glm::vec2, bool>
-find_arc_centre(glm::vec2 as, float entrys, glm::vec2 bs, float entrye)
+std::pair<Position2D, bool>
+find_arc_centre(Position2D as, float entrys, Position2D bs, float entrye)
 {
 	if (as == bs) {
 		return {as, false};
@@ -129,8 +129,8 @@ find_arc_centre(glm::vec2 as, float entrys, glm::vec2 bs, float entrye)
 	return find_arc_centre(as, sincosf(entrys + half_pi), bs, sincosf(entrye - half_pi));
 }
 
-std::pair<glm::vec2, bool>
-find_arc_centre(glm::vec2 as, glm::vec2 ad, glm::vec2 bs, glm::vec2 bd)
+std::pair<Position2D, bool>
+find_arc_centre(Position2D as, Position2D ad, Position2D bs, Position2D bd)
 {
 	const auto det = bd.x * ad.y - bd.y * ad.x;
 	if (det != 0) { // near parallel line will yield noisy results
@@ -142,7 +142,7 @@ find_arc_centre(glm::vec2 as, glm::vec2 ad, glm::vec2 bs, glm::vec2 bd)
 }
 
 std::pair<float, float>
-find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye)
+find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye)
 {
 	const auto getrad = [&](float leftOrRight) {
 		return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight));
@@ -151,7 +151,7 @@ find_arcs_radius(glm::vec2 start, float entrys, glm::vec2 end, float entrye)
 }
 
 float
-find_arcs_radius(glm::vec2 start, glm::vec2 ad, glm::vec2 end, glm::vec2 bd)
+find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd)
 {
 	// Short name functions for big forula
 	auto sqrt = [](float v) {
diff --git a/lib/ray.cpp b/lib/ray.cpp
index c4e0d8c..9fb3648 100644
--- a/lib/ray.cpp
+++ b/lib/ray.cpp
@@ -2,13 +2,13 @@
 #include <algorithm>
 
 Ray
-Ray::fromPoints(glm::vec3 start, glm::vec3 p)
+Ray::fromPoints(Position3D start, Position3D p)
 {
 	return {start, glm::normalize(p - start)};
 }
 
 float
-Ray::distanceToLine(const glm::vec3 & p1, const glm::vec3 & e1) const
+Ray::distanceToLine(const Position3D & p1, const Position3D & e1) const
 {
 	// https://en.wikipedia.org/wiki/Skew_lines
 	const auto diff = p1 - e1;
@@ -25,10 +25,10 @@ Ray::distanceToLine(const glm::vec3 & p1, const glm::vec3 & e1) const
 }
 
 bool
-Ray::passesCloseToEdges(const std::span<const glm::vec3> positions, float distance) const
+Ray::passesCloseToEdges(const std::span<const Position3D> positions, float distance) const
 {
 	return std::adjacent_find(positions.begin(), positions.end(),
-				   [this, distance](const glm::vec3 & a, const glm::vec3 & b) {
+				   [this, distance](const Position3D & a, const Position3D & b) {
 					   return distanceToLine(a, b) <= distance;
 				   })
 			!= positions.end();
diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp
index 177ab6a..9af08cb 100644
--- a/test/test-assetFactory.cpp
+++ b/test/test-assetFactory.cpp
@@ -25,7 +25,7 @@ BOOST_GLOBAL_FIXTURE(TestMainWindow);
 
 const std::filesystem::path TMP {"/tmp"};
 
-class FactoryFixture : public TestRenderOutputSize<glm::ivec2 {2048, 1024}>, public SceneProvider {
+class FactoryFixture : public TestRenderOutputSize<TextureAbsCoord {2048, 1024}>, public SceneProvider {
 public:
 	FactoryFixture() : sceneRenderer {size, output} { }
 
diff --git a/test/testRenderOutput.cpp b/test/testRenderOutput.cpp
index 464b0b3..9af4451 100644
--- a/test/testRenderOutput.cpp
+++ b/test/testRenderOutput.cpp
@@ -1,7 +1,7 @@
 #include "testRenderOutput.h"
 #include <stdexcept>
 
-TestRenderOutput::TestRenderOutput(glm::ivec2 s) : size {s}
+TestRenderOutput::TestRenderOutput(TextureAbsCoord s) : size {s}
 {
 	glBindFramebuffer(GL_FRAMEBUFFER, output);
 	const auto configuregdata
diff --git a/ui/builders/straight.cpp b/ui/builders/straight.cpp
index 4fa9585..9b262bb 100644
--- a/ui/builders/straight.cpp
+++ b/ui/builders/straight.cpp
@@ -47,7 +47,7 @@ BuilderStraight::click(Network * network, const GeoData * geoData, const SDL_Mou
 }
 
 void
-BuilderStraight::create(Network * network, glm::vec3 p1, glm::vec3 p2) const
+BuilderStraight::create(Network * network, Position3D p1, Position3D p2) const
 {
 	network->addStraight(p1, p2);
 }
diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp
index 808e0e4..a451ee1 100644
--- a/ui/gameMainSelector.cpp
+++ b/ui/gameMainSelector.cpp
@@ -8,6 +8,7 @@
 #include <game/selectable.h>
 #include <game/worldobject.h> // IWYU pragma: keep
 #include <gfx/gl/camera.h>
+#include <math.h>
 #include <optional>
 #include <span>
 #include <stream_support.h>
@@ -16,7 +17,7 @@
 
 GameMainSelector::GameMainSelector(const Camera * c, ScreenAbsCoord size) : UIComponent {{{}, size}}, camera {c} { }
 
-constexpr glm::vec2 TargetPos {5, 45};
+constexpr ScreenAbsCoord TargetPos {5, 45};
 
 void
 GameMainSelector::render(const UIShader & shader, const Position & parentPos) const
@@ -41,7 +42,7 @@ bool
 GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos)
 {
 	const auto getRay = [this](const auto & e) {
-		const auto mouse = glm::vec2 {e.x, e.y} / position.size;
+		const auto mouse = ScreenRelCoord {e.x, e.y} / position.size;
 		return camera->unProject(mouse);
 	};
 	if (target) {
@@ -72,8 +73,8 @@ GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos)
 void
 GameMainSelector::defaultClick(const Ray & ray)
 {
-	glm::vec2 baryPos {};
-	float distance;
+	Position2D baryPos {};
+	float distance {};
 
 	if (const auto selected
 			= gameState->world.applyOne<Selectable>(&Selectable::intersectRay, ray, &baryPos, &distance);
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
index b94accd..15f1e07 100644
--- a/ui/gameMainWindow.cpp
+++ b/ui/gameMainWindow.cpp
@@ -31,8 +31,8 @@ public:
 GameMainWindow::GameMainWindow(size_t w, size_t h) :
 	Window {w, h, "I Like Trains", SDL_WINDOW_OPENGL}, SceneRenderer {Window::size, 0}
 {
-	uiComponents.create<ManualCameraController>(glm::vec2 {-1150, -1150});
-	auto gms = uiComponents.create<GameMainSelector>(&camera, glm::vec2 {w, h});
+	uiComponents.create<ManualCameraController>(Position2D {-1150, -1150});
+	auto gms = uiComponents.create<GameMainSelector>(&camera, ScreenAbsCoord {w, h});
 	uiComponents.create<GameMainToolbar>(gms.get());
 }
 
diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp
index 8e52b0e..05c1fc5 100644
--- a/ui/manualCameraController.cpp
+++ b/ui/manualCameraController.cpp
@@ -59,7 +59,7 @@ ManualCameraController::handleInput(const SDL_Event & e, const Position &)
 					pitch = std::clamp(pitch - 0.01F * static_cast<float>(e.motion.yrel), 0.1F, half_pi);
 				}
 				else {
-					focus += rotate_flat(-direction) * glm::vec2 {-e.motion.xrel, e.motion.yrel};
+					focus += rotate_flat(-direction) * Position2D {-e.motion.xrel, e.motion.yrel};
 				}
 			}
 			return true;
-- 
cgit v1.2.3


From 5bc0462311ab4c691102f0bc39d6ae03c61a287b Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sat, 11 Nov 2023 17:32:05 +0000
Subject: Add Location method for getting the rotation only transform

---
 lib/location.cpp | 6 ++++++
 lib/location.h   | 1 +
 2 files changed, 7 insertions(+)

(limited to 'lib')

diff --git a/lib/location.cpp b/lib/location.cpp
index 732dd6d..9a31402 100644
--- a/lib/location.cpp
+++ b/lib/location.cpp
@@ -7,3 +7,9 @@ Location::getTransform() const
 {
 	return glm::translate(pos) * rotate_ypr(rot);
 }
+
+glm::mat4
+Location::getRotationTransform() const
+{
+	return rotate_ypr(rot);
+}
diff --git a/lib/location.h b/lib/location.h
index 7f2b44d..55737ae 100644
--- a/lib/location.h
+++ b/lib/location.h
@@ -10,6 +10,7 @@ public:
 #endif
 
 	[[nodiscard]] glm::mat4 getTransform() const;
+	[[nodiscard]] glm::mat4 getRotationTransform() const;
 
 	Position3D pos;
 	Rotation3D rot;
-- 
cgit v1.2.3


From 3200eb41d60595813dca751fe15193ba0b44dddf Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sat, 25 Nov 2023 14:32:56 +0000
Subject: Remove getTransform

---
 game/vehicles/railVehicle.cpp | 18 +++++++++---------
 gfx/gl/bufferedLocation.cpp   |  6 ------
 gfx/gl/bufferedLocation.h     |  1 -
 lib/location.cpp              |  6 ------
 lib/location.h                |  1 -
 5 files changed, 9 insertions(+), 23 deletions(-)

(limited to 'lib')

diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index 26536f5..bee0dd0 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -49,16 +49,16 @@ RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distanc
 	constexpr const auto X = 1350.F;
 	const auto Y = this->rvClass->length / 2.F;
 	constexpr const auto Z = 3900.F;
-	const auto moveBy = location.getTransform();
+	const auto moveBy = location.getRotationTransform();
 	const std::array<Position3D, 8> cornerVertices {{
-			moveBy * glm::vec4 {-X, Y, 0, 1}, //  LFB
-			moveBy * glm::vec4 {X, Y, 0, 1}, //   RFB
-			moveBy * glm::vec4 {-X, Y, Z, 1}, //  LFT
-			moveBy * glm::vec4 {X, Y, Z, 1}, //   RFT
-			moveBy * glm::vec4 {-X, -Y, 0, 1}, // LBB
-			moveBy * glm::vec4 {X, -Y, 0, 1}, //  RBB
-			moveBy * glm::vec4 {-X, -Y, Z, 1}, // LBT
-			moveBy * glm::vec4 {X, -Y, Z, 1}, //  RBT
+			location.position() + (moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), //  LFB
+			location.position() + (moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), //   RFB
+			location.position() + (moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), //  LFT
+			location.position() + (moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), //   RFT
+			location.position() + (moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB
+			location.position() + (moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), //  RBB
+			location.position() + (moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT
+			location.position() + (moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), //  RBT
 	}};
 	static constexpr const std::array<glm::vec<3, uint8_t>, 10> triangles {{
 			// Front
diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp
index 412e3ab..2a2e723 100644
--- a/gfx/gl/bufferedLocation.cpp
+++ b/gfx/gl/bufferedLocation.cpp
@@ -57,12 +57,6 @@ BufferedLocation::setLocation(Position3D p, Rotation3D r)
 	updateBuffer();
 }
 
-glm::mat4
-BufferedLocation::getTransform() const
-{
-	return loc.getTransform();
-}
-
 glm::mat4
 BufferedLocation::getRotationTransform() const
 {
diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h
index a5cd23e..30967e3 100644
--- a/gfx/gl/bufferedLocation.h
+++ b/gfx/gl/bufferedLocation.h
@@ -22,7 +22,6 @@ public:
 	void setRotation(Rotation3D, bool update = true);
 	void setLocation(Position3D, Rotation3D);
 
-	[[nodiscard]] glm::mat4 getTransform() const;
 	[[nodiscard]] glm::mat4 getRotationTransform() const;
 
 private:
diff --git a/lib/location.cpp b/lib/location.cpp
index 9a31402..ff7cfa6 100644
--- a/lib/location.cpp
+++ b/lib/location.cpp
@@ -2,12 +2,6 @@
 #include "maths.h"
 #include <glm/gtx/transform.hpp>
 
-glm::mat4
-Location::getTransform() const
-{
-	return glm::translate(pos) * rotate_ypr(rot);
-}
-
 glm::mat4
 Location::getRotationTransform() const
 {
diff --git a/lib/location.h b/lib/location.h
index 55737ae..85834a0 100644
--- a/lib/location.h
+++ b/lib/location.h
@@ -9,7 +9,6 @@ public:
 	explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { }
 #endif
 
-	[[nodiscard]] glm::mat4 getTransform() const;
 	[[nodiscard]] glm::mat4 getRotationTransform() const;
 
 	Position3D pos;
-- 
cgit v1.2.3


From 0aa665c3648d788755b00c9e431c872d57fddbb8 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sat, 25 Nov 2023 16:28:39 +0000
Subject: Model positions as integers

Introduces test failure in arcs due to rounding, but I don't want to create a complicated
fix as link positions are still floats and hopefully that'll go away... somehow
---
 config/types.h                           | 19 +++++++++++++++----
 game/geoData.cpp                         |  4 ++--
 game/scenary/foliage.h                   |  2 +-
 game/vehicles/railVehicle.cpp            | 22 +++++++++++-----------
 game/vehicles/railVehicleClass.h         |  2 +-
 gfx/followCameraController.cpp           |  4 ++--
 gfx/gl/bufferedLocation.cpp              |  8 ++++----
 gfx/gl/bufferedLocation.h                |  8 ++++----
 gfx/gl/sceneShader.cpp                   |  2 +-
 gfx/gl/shaders/dynamicPoint.vs           |  2 +-
 gfx/gl/shaders/dynamicPointInst.vs       |  2 +-
 gfx/gl/shaders/fixedPoint.vs             |  2 +-
 gfx/gl/shaders/shadowDynamicPoint.vs     |  2 +-
 gfx/gl/shaders/shadowDynamicPointInst.vs |  2 +-
 gfx/gl/shaders/shadowFixedPoint.vs       |  2 +-
 gfx/gl/shadowMapper.cpp                  |  2 +-
 lib/location.h                           |  4 ++--
 test/test-maths.cpp                      | 12 ++++++------
 18 files changed, 56 insertions(+), 45 deletions(-)

(limited to 'lib')

diff --git a/config/types.h b/config/types.h
index d99735e..6fc7b61 100644
--- a/config/types.h
+++ b/config/types.h
@@ -3,10 +3,14 @@
 #include "glad/gl.h"
 #include <glm/geometric.hpp>
 
-using Distance = float;
+using Distance = float; // deprecate
+using RelativeDistance = float;
+using GlobalDistance = int32_t;
 using Angle = float;
 
-template<glm::length_t D> using Position = glm::vec<D, Distance>;
+template<glm::length_t D> using Position = glm::vec<D, Distance>; // deprecate
+template<glm::length_t D> using RelativePosition = glm::vec<D, RelativeDistance>;
+template<glm::length_t D> using GlobalPosition = glm::vec<D, GlobalDistance>;
 template<glm::length_t D> using Size = glm::vec<D, Distance>;
 template<glm::length_t D> using Scale = glm::vec<D, float>;
 template<glm::length_t D> using Direction = glm::vec<D, float>;
@@ -14,8 +18,15 @@ template<glm::length_t D> using Normal = Direction<D>;
 template<glm::length_t D> using Rotation = glm::vec<D, Angle>;
 template<glm::length_t Channels> using Colour = glm::vec<Channels, float>;
 
-using Position2D = Position<2>;
-using Position3D = Position<3>;
+using Position2D = Position<2>; // deprecate
+using Position3D = Position<3>; // deprecate
+using BaryPosition = glm::vec<2, float>;
+using RelativePosition2D = RelativePosition<2>;
+using RelativePosition3D = RelativePosition<3>;
+using RelativePosition4D = RelativePosition<4>;
+using GlobalPosition2D = GlobalPosition<2>;
+using GlobalPosition3D = GlobalPosition<3>;
+using GlobalPosition4D = GlobalPosition<4>;
 using Size2D = Size<2>;
 using Size3D = Size<3>;
 using Scale2D = Scale<2>;
diff --git a/game/geoData.cpp b/game/geoData.cpp
index da067f7..ec990ea 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -73,7 +73,7 @@ GeoData::loadFromImages(const std::filesystem::path & fileName, float scale_)
 }
 
 GeoData::Quad
-GeoData::quad(glm::vec2 wcoord) const
+GeoData::quad(Position2D wcoord) const
 {
 	constexpr static const std::array<glm::vec2, 4> corners {{{0, 0}, {0, 1}, {1, 0}, {1, 1}}};
 	return transform_array(transform_array(corners,
@@ -154,7 +154,7 @@ GeoData::intersectRay(const Ray & ray) const
 		try {
 			const auto point = quad(n);
 			for (auto offset : {0U, 1U}) {
-				glm::vec2 bary;
+				BaryPosition bary;
 				float distance;
 				if (glm::intersectRayTriangle(ray.start, ray.direction, point[offset], point[offset + 1],
 							point[offset + 2], bary, distance)) {
diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h
index 5a9d2de..bbb6200 100644
--- a/game/scenary/foliage.h
+++ b/game/scenary/foliage.h
@@ -15,7 +15,7 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs<Foliage> {
 	glVertexArray instanceVAO;
 
 public:
-	using LocationVertex = std::pair<glm::mat4, Position3D>;
+	using LocationVertex = std::pair<glm::mat4, GlobalPosition3D>;
 	mutable InstanceVertices<LocationVertex> instances;
 	void render(const SceneShader &) const override;
 	void shadows(const ShadowMapper &) const override;
diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index bee0dd0..30b615c 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -38,9 +38,9 @@ RailVehicle::move(const Train * t, float & trailBy)
 	const auto overhang {(rvClass->length - rvClass->wheelBase) / 2};
 	const auto & b1Pos = bogies[0] = t->getBogiePosition(t->linkDist, trailBy += overhang);
 	const auto & b2Pos = bogies[1] = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase);
-	const auto diff = glm::normalize(b2Pos.position() - b1Pos.position());
-	location.setLocation((b1Pos.position() + b2Pos.position()) / 2.F, {vector_pitch(diff), vector_yaw(diff), 0});
-	trailBy += 0.6F + overhang;
+	const auto diff = glm::normalize(RelativePosition3D(b2Pos.position() - b1Pos.position()));
+	location.setLocation((b1Pos.position() + b2Pos.position()) / 2, {vector_pitch(diff), vector_yaw(diff), 0});
+	trailBy += 600.F + overhang;
 }
 
 bool
@@ -51,14 +51,14 @@ RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distanc
 	constexpr const auto Z = 3900.F;
 	const auto moveBy = location.getRotationTransform();
 	const std::array<Position3D, 8> cornerVertices {{
-			location.position() + (moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), //  LFB
-			location.position() + (moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), //   RFB
-			location.position() + (moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), //  LFT
-			location.position() + (moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), //   RFT
-			location.position() + (moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB
-			location.position() + (moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), //  RBB
-			location.position() + (moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT
-			location.position() + (moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), //  RBT
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, 0, 1}).xyz(), //  LFB
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, 0, 1}).xyz(), //   RFB
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, Y, Z, 1}).xyz(), //  LFT
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, Y, Z, 1}).xyz(), //   RFT
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, 0, 1}).xyz(), // LBB
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, 0, 1}).xyz(), //  RBB
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {-X, -Y, Z, 1}).xyz(), // LBT
+			location.position() + GlobalPosition3D(moveBy * glm::vec4 {X, -Y, Z, 1}).xyz(), //  RBT
 	}};
 	static constexpr const std::array<glm::vec<3, uint8_t>, 10> triangles {{
 			// Front
diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h
index 16dce01..913feea 100644
--- a/game/vehicles/railVehicleClass.h
+++ b/game/vehicles/railVehicleClass.h
@@ -20,7 +20,7 @@ public:
 
 	struct LocationVertex {
 		glm::mat4 body, front, back;
-		Position3D bodyPos, frontPos, backPos;
+		GlobalPosition3D bodyPos, frontPos, backPos;
 	};
 
 	std::array<Mesh::Ptr, 2> bogies;
diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp
index 5b08483..aee2187 100644
--- a/gfx/followCameraController.cpp
+++ b/gfx/followCameraController.cpp
@@ -24,11 +24,11 @@ FollowCameraController::updateCamera(Camera * camera) const
 			break;
 
 		case Mode::Ride:
-			camera->setView(pos + (up * 4.8F), !-sincosf(rot.y));
+			camera->setView(pos + GlobalPosition3D(up * 4.8F), !-sincosf(rot.y));
 			break;
 
 		case Mode::ISO:
-			camera->setView(pos + ((up + north + east) * 40.F), glm::normalize(down + south + west),
+			camera->setView(pos + GlobalPosition3D((up + north + east) * 40.F), glm::normalize(down + south + west),
 					glm::normalize(up - north - east));
 			break;
 	}
diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp
index 2a2e723..d6a63b9 100644
--- a/gfx/gl/bufferedLocation.cpp
+++ b/gfx/gl/bufferedLocation.cpp
@@ -2,7 +2,7 @@
 #include "location.h"
 #include <glm/gtx/transform.hpp>
 
-BufferedLocation::BufferedLocation(Position3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { }
+BufferedLocation::BufferedLocation(GlobalPosition3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { }
 
 BufferedLocation::BufferedLocation(const Location & l) : loc {l} { }
 
@@ -19,7 +19,7 @@ BufferedLocation::operator=(const Location & l)
 	return *this;
 }
 
-Position3D
+GlobalPosition3D
 BufferedLocation::position() const
 {
 	return loc.pos;
@@ -32,7 +32,7 @@ BufferedLocation::rotation() const
 }
 
 void
-BufferedLocation::setPosition(Position3D p, bool update)
+BufferedLocation::setPosition(GlobalPosition3D p, bool update)
 {
 	loc.pos = p;
 	if (update) {
@@ -50,7 +50,7 @@ BufferedLocation::setRotation(Position3D r, bool update)
 }
 
 void
-BufferedLocation::setLocation(Position3D p, Rotation3D r)
+BufferedLocation::setLocation(GlobalPosition3D p, Rotation3D r)
 {
 	loc.pos = p;
 	loc.rot = r;
diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h
index 30967e3..87b957f 100644
--- a/gfx/gl/bufferedLocation.h
+++ b/gfx/gl/bufferedLocation.h
@@ -8,7 +8,7 @@
 
 class BufferedLocation {
 public:
-	BufferedLocation(Position3D = {}, Rotation3D = {});
+	BufferedLocation(GlobalPosition3D = {}, Rotation3D = {});
 	BufferedLocation(const Location &);
 	virtual ~BufferedLocation() = default;
 
@@ -16,11 +16,11 @@ public:
 
 	operator const Location &() const;
 
-	[[nodiscard]] Position3D position() const;
+	[[nodiscard]] GlobalPosition3D position() const;
 	[[nodiscard]] Rotation3D rotation() const;
-	void setPosition(Position3D, bool update = true);
+	void setPosition(GlobalPosition3D, bool update = true);
 	void setRotation(Rotation3D, bool update = true);
-	void setLocation(Position3D, Rotation3D);
+	void setLocation(GlobalPosition3D, Rotation3D);
 
 	[[nodiscard]] glm::mat4 getRotationTransform() const;
 
diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp
index de75814..59a9748 100644
--- a/gfx/gl/sceneShader.cpp
+++ b/gfx/gl/sceneShader.cpp
@@ -69,7 +69,7 @@ void
 SceneShader::BasicProgram::setModel(Location const & location) const
 {
 	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot)));
-	glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos));
+	glUniform3iv(modelPosLoc, 1, glm::value_ptr(location.pos));
 }
 
 void
diff --git a/gfx/gl/shaders/dynamicPoint.vs b/gfx/gl/shaders/dynamicPoint.vs
index 9dd6a47..667f247 100644
--- a/gfx/gl/shaders/dynamicPoint.vs
+++ b/gfx/gl/shaders/dynamicPoint.vs
@@ -7,6 +7,6 @@ include(`materialInterface.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 uniform mat4 model;
-uniform vec3 modelPos;
+uniform ivec3 modelPos;
 
 include(`commonPoint.glsl')
diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs
index 4ae6813..adf39bd 100644
--- a/gfx/gl/shaders/dynamicPointInst.vs
+++ b/gfx/gl/shaders/dynamicPointInst.vs
@@ -7,6 +7,6 @@ include(`materialInterface.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 layout(location = 5) in mat4 model;
-layout(location = 9) in vec3 modelPos;
+layout(location = 9) in ivec3 modelPos;
 
 include(`commonPoint.glsl')
diff --git a/gfx/gl/shaders/fixedPoint.vs b/gfx/gl/shaders/fixedPoint.vs
index 0adbb02..6e1ab49 100644
--- a/gfx/gl/shaders/fixedPoint.vs
+++ b/gfx/gl/shaders/fixedPoint.vs
@@ -7,6 +7,6 @@ include(`materialInterface.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 const mat4 model = mat4(1);
-const vec3 modelPos = vec3(0);
+const vec3 modelPos = ivec3(0);
 
 include(`commonPoint.glsl')
diff --git a/gfx/gl/shaders/shadowDynamicPoint.vs b/gfx/gl/shaders/shadowDynamicPoint.vs
index eb25423..e20d31a 100644
--- a/gfx/gl/shaders/shadowDynamicPoint.vs
+++ b/gfx/gl/shaders/shadowDynamicPoint.vs
@@ -5,6 +5,6 @@ include(`meshIn.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 uniform mat4 model;
-uniform vec3 modelPos;
+uniform ivec3 modelPos;
 
 include(`commonShadowPoint.glsl')
diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vs b/gfx/gl/shaders/shadowDynamicPointInst.vs
index a0f51c3..ab3e976 100644
--- a/gfx/gl/shaders/shadowDynamicPointInst.vs
+++ b/gfx/gl/shaders/shadowDynamicPointInst.vs
@@ -5,6 +5,6 @@ include(`meshIn.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 layout(location = 5) in mat4 model;
-layout(location = 9) in vec3 modelPos;
+layout(location = 9) in ivec3 modelPos;
 
 include(`commonShadowPoint.glsl')
diff --git a/gfx/gl/shaders/shadowFixedPoint.vs b/gfx/gl/shaders/shadowFixedPoint.vs
index dfc5c42..a9fb4a3 100644
--- a/gfx/gl/shaders/shadowFixedPoint.vs
+++ b/gfx/gl/shaders/shadowFixedPoint.vs
@@ -5,6 +5,6 @@ include(`meshIn.glsl')
 uniform mat4 viewProjection;
 uniform vec3 viewPoint;
 const mat4 model = mat4(1);
-const vec3 modelPos = vec3(0);
+const ivec3 modelPos = ivec3(0);
 
 include(`commonShadowPoint.glsl')
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 4a8d7ec..07db6a1 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -202,5 +202,5 @@ void
 ShadowMapper::DynamicPoint::setModel(const Location & location) const
 {
 	glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(rotate_ypr(location.rot)));
-	glUniform3fv(modelPosLoc, 1, glm::value_ptr(location.pos));
+	glUniform3iv(modelPosLoc, 1, glm::value_ptr(location.pos));
 }
diff --git a/lib/location.h b/lib/location.h
index 85834a0..8570fc2 100644
--- a/lib/location.h
+++ b/lib/location.h
@@ -6,11 +6,11 @@
 class Location {
 public:
 #ifndef __cpp_aggregate_paren_init
-	explicit Location(Position3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { }
+	explicit Location(GlobalPosition3D pos = {}, Rotation3D rot = {}) : pos {pos}, rot {rot} { }
 #endif
 
 	[[nodiscard]] glm::mat4 getRotationTransform() const;
 
-	Position3D pos;
+	GlobalPosition3D pos;
 	Rotation3D rot;
 };
diff --git a/test/test-maths.cpp b/test/test-maths.cpp
index 2560319..9eae918 100644
--- a/test/test-maths.cpp
+++ b/test/test-maths.cpp
@@ -196,12 +196,12 @@ BOOST_DATA_TEST_CASE(straight1,
 	const TestLinkStraight l(v);
 	{
 		const auto p = l.positionAt(0, 0);
-		BOOST_CHECK_EQUAL(p.pos, origin);
+		BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {origin});
 		BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angFor, 0));
 	}
 	{
 		const auto p = l.positionAt(0, 1);
-		BOOST_CHECK_EQUAL(p.pos, v);
+		BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {v});
 		BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angBack, 0));
 	}
 }
@@ -231,12 +231,12 @@ BOOST_DATA_TEST_CASE(curve1,
 		BOOST_CHECK_EQUAL(l.radius, 1.F);
 		{
 			const auto p = l.positionAt(0, 0);
-			BOOST_CHECK_CLOSE_VEC(p.pos, origin);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin);
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angFor, 0));
 		}
 		{
 			const auto p = l.positionAt(0, 1);
-			BOOST_CHECK_CLOSE_VEC(p.pos, e1);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1);
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBack, 0));
 		}
 	}
@@ -247,13 +247,13 @@ BOOST_DATA_TEST_CASE(curve1,
 		{
 			const auto p = l.positionAt(0, 0);
 			const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor);
-			BOOST_CHECK_CLOSE_VEC(p.pos, e1);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, e1);
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angForReversed, 0));
 		}
 		{
 			const auto p = l.positionAt(0, 1);
 			const auto angBackReversed = normalize(vector_yaw(e1 - origin) * 2 - angBack);
-			BOOST_CHECK_CLOSE_VEC(p.pos, origin);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin);
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0));
 		}
 	}
-- 
cgit v1.2.3


From 0a5d23ce263551bab3759e4ac65ecb6cfebdc892 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sat, 2 Dec 2023 12:23:52 +0000
Subject: Add crossInt - cross product for integer vectors

---
 lib/maths.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

(limited to 'lib')

diff --git a/lib/maths.h b/lib/maths.h
index 67b2a15..cf369a7 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -67,6 +67,17 @@ sq(T v)
 	return v * v;
 }
 
+template<std::integral T, glm::qualifier Q>
+inline constexpr glm::vec<3, T, Q>
+crossInt(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+{
+	return {
+			(a.y * b.z) - (a.z * b.y),
+			(a.z * b.x) - (a.x * b.z),
+			(a.x * b.y) - (a.y * b.x),
+	};
+}
+
 template<typename R = float, typename Ta, typename Tb>
 inline constexpr auto
 ratio(Ta a, Tb b)
-- 
cgit v1.2.3


From 0841ead91c49a212134f19f7c0b411984b0fda29 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Fri, 29 Dec 2023 13:20:55 +0000
Subject: Remove weird operator! on vec2/3

---
 game/network/link.cpp          |  2 +-
 game/network/network.cpp       |  4 ++--
 game/network/rail.cpp          |  4 ++--
 gfx/followCameraController.cpp |  2 +-
 lib/maths.cpp                  |  2 +-
 lib/maths.h                    | 12 ------------
 ui/manualCameraController.cpp  |  2 +-
 7 files changed, 8 insertions(+), 20 deletions(-)

(limited to 'lib')

diff --git a/game/network/link.cpp b/game/network/link.cpp
index 498afe4..d8479dd 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -46,7 +46,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const
 	const auto es {std::make_pair(ends[start].node.get(), ends[1 - start].node.get())};
 	const auto as {std::make_pair(arc[start], arc[1 - start])};
 	const auto ang {as.first + ((as.second - as.first) * frac)};
-	const auto relPos {!sincosf(ang) * radius};
+	const auto relPos {sincosf(ang) ^ 0.F * radius};
 	const auto relClimb {vehiclePositionOffset()
 			+ Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}};
 	const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})};
diff --git a/game/network/network.cpp b/game/network/network.cpp
index d18345c..5de2f5d 100644
--- a/game/network/network.cpp
+++ b/game/network/network.cpp
@@ -100,7 +100,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta
 	const auto diff {end - start};
 	const auto vy {vector_yaw(diff)};
 	const auto dir = pi + startDir;
-	const auto flatStart {!start}, flatEnd {!end};
+	const auto flatStart {start.xy()}, flatEnd {end.xy()};
 	const auto n2ed {(vy * 2) - dir - pi};
 	const auto centre {find_arc_centre(flatStart, dir, flatEnd, n2ed)};
 
@@ -115,7 +115,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta
 {
 	startDir += pi;
 	endDir += pi;
-	const Position2D flatStart {!start}, flatEnd {!end};
+	const Position2D flatStart {start.xy()}, flatEnd {end.xy()};
 	auto midheight = [&](auto mid) {
 		const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid);
 		return start.z + ((end.z - start.z) * (sm / (sm + em)));
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index ff101d4..545a728 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -45,7 +45,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end)
 	if (dir == vector_yaw(end - start)) {
 		return addLink<RailLinkStraight>(start, end);
 	}
-	const Position2D flatStart {!start}, flatEnd {!end};
+	const Position2D flatStart {start.xy()}, flatEnd {end.xy()};
 	if (node2ins.second == NodeIs::InNetwork) {
 		auto midheight = [&](auto mid) {
 			const auto sm = glm::distance(flatStart, mid), em = glm::distance(flatEnd, mid);
@@ -142,7 +142,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D &
 }
 
 RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) :
-	RailLinkCurve(a, b, c ^ a->pos.z, {!c, a->pos, b->pos})
+	RailLinkCurve(a, b, c ^ a->pos.z, {c ^ 0.F, a->pos, b->pos})
 {
 }
 
diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp
index aee2187..9b23173 100644
--- a/gfx/followCameraController.cpp
+++ b/gfx/followCameraController.cpp
@@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const
 			break;
 
 		case Mode::Ride:
-			camera->setView(pos + GlobalPosition3D(up * 4.8F), !-sincosf(rot.y));
+			camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) ^ 0.F);
 			break;
 
 		case Mode::ISO:
diff --git a/lib/maths.cpp b/lib/maths.cpp
index 5430ef6..0c25820 100644
--- a/lib/maths.cpp
+++ b/lib/maths.cpp
@@ -9,7 +9,7 @@ glm::mat4
 flat_orientation(const Direction3D & diff)
 {
 	static const auto oneeighty {glm::rotate(pi, up)};
-	const auto flatdiff {glm::normalize(!!diff)};
+	const auto flatdiff {glm::normalize(diff.xy() ^ 0.F)};
 	auto e {glm::orientation(flatdiff, north)};
 	// Handle if diff is exactly opposite to north
 	return (std::isnan(e[0][0])) ? oneeighty : e;
diff --git a/lib/maths.h b/lib/maths.h
index cf369a7..dd83c4b 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -99,12 +99,6 @@ perspective_divide(glm::vec<4, T, Q> v)
 	return v / v.w;
 }
 
-constexpr inline Position2D
-operator!(const Position3D & v)
-{
-	return {v.x, v.y};
-}
-
 constexpr inline Position3D
 operator^(const Position2D & v, float z)
 {
@@ -117,12 +111,6 @@ operator^(const Position3D & v, float w)
 	return {v.x, v.y, v.z, w};
 }
 
-constexpr inline Position3D
-operator!(const Position2D & v)
-{
-	return v ^ 0.F;
-}
-
 template<glm::length_t L1, glm::length_t L2, typename T, glm::qualifier Q>
 inline constexpr glm::vec<L1 + L2, T, Q>
 operator||(const glm::vec<L1, T, Q> v1, const glm::vec<L2, T, Q> v2)
diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp
index f6993a8..1f6b510 100644
--- a/ui/manualCameraController.cpp
+++ b/ui/manualCameraController.cpp
@@ -79,5 +79,5 @@ void
 ManualCameraController::updateCamera(Camera * camera) const
 {
 	const auto forward = glm::normalize(sincosf(direction) ^ -sin(pitch));
-	camera->setView(!focus - forward * 3.F * std::pow(dist, 1.3F), forward);
+	camera->setView((focus ^ 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward);
 }
-- 
cgit v1.2.3


From 048f18e2a0b32044525cef41fa053984433c74b9 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Fri, 29 Dec 2023 14:12:40 +0000
Subject: Remove misleading power operator^ on vec2/3

---
 assetFactory/cylinder.cpp      |  6 +++---
 game/network/link.cpp          |  2 +-
 game/network/network.cpp       |  4 ++--
 game/network/rail.cpp          | 10 +++++-----
 gfx/followCameraController.cpp |  2 +-
 gfx/gl/camera.cpp              |  2 +-
 lib/maths.cpp                  |  2 +-
 lib/maths.h                    | 24 +++++++-----------------
 ui/manualCameraController.cpp  |  4 ++--
 9 files changed, 23 insertions(+), 33 deletions(-)

(limited to 'lib')

diff --git a/assetFactory/cylinder.cpp b/assetFactory/cylinder.cpp
index ed034fd..58980cf 100644
--- a/assetFactory/cylinder.cpp
+++ b/assetFactory/cylinder.cpp
@@ -19,7 +19,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const
 		// Generate bottom face vertices
 		std::vector<OpenMesh::VertexHandle> bottom(P);
 		std::transform(circumference.begin(), circumference.end(), bottom.begin(), [&mesh](const auto & xy) {
-			return mesh.add_vertex(xy ^ 0.F);
+			return mesh.add_vertex(xy || 0.F);
 		});
 		surface.insert(mesh.add_namedFace("bottom", bottom));
 	}
@@ -27,7 +27,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const
 		// Generate top face vertices
 		std::vector<OpenMesh::VertexHandle> top(P);
 		std::transform(circumference.rbegin(), circumference.rend(), top.begin(), [&mesh](const auto & xy) {
-			return mesh.add_vertex(xy ^ 1);
+			return mesh.add_vertex(xy || 1.F);
 		});
 		surface.insert(mesh.add_namedFace("top", top));
 	}
@@ -35,7 +35,7 @@ Cylinder::createMesh(ModelFactoryMesh & mesh, float lodf) const
 		// Generate edge vertices
 		std::vector<std::pair<OpenMesh::VertexHandle, OpenMesh::VertexHandle>> edge(P + 1);
 		std::transform(circumference.begin(), circumference.end(), edge.begin(), [&mesh](const auto & xy) {
-			return std::make_pair(mesh.add_vertex(xy ^ 0), mesh.add_vertex(xy ^ 1));
+			return std::make_pair(mesh.add_vertex(xy || 0.F), mesh.add_vertex(xy || 1.F));
 		});
 		// Wrap around
 		edge.back() = edge.front();
diff --git a/game/network/link.cpp b/game/network/link.cpp
index d8479dd..703a1ca 100644
--- a/game/network/link.cpp
+++ b/game/network/link.cpp
@@ -46,7 +46,7 @@ LinkCurve::positionAt(float dist, unsigned char start) const
 	const auto es {std::make_pair(ends[start].node.get(), ends[1 - start].node.get())};
 	const auto as {std::make_pair(arc[start], arc[1 - start])};
 	const auto ang {as.first + ((as.second - as.first) * frac)};
-	const auto relPos {sincosf(ang) ^ 0.F * radius};
+	const auto relPos {(sincosf(ang) || 0.F) * radius};
 	const auto relClimb {vehiclePositionOffset()
 			+ Position3D {0, 0, es.first->pos.z - centreBase.z + ((es.second->pos.z - es.first->pos.z) * frac)}};
 	const auto pitch {vector_pitch({0, 0, (es.second->pos.z - es.first->pos.z) / length})};
diff --git a/game/network/network.cpp b/game/network/network.cpp
index 5de2f5d..1ff5b26 100644
--- a/game/network/network.cpp
+++ b/game/network/network.cpp
@@ -125,7 +125,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta
 		const auto c1 = flatStart + sincosf(startDir + half_pi) * radius;
 		const auto c2 = flatEnd + sincosf(endDir + half_pi) * radius;
 		const auto mid = (c1 + c2) / 2.F;
-		const auto midh = mid ^ midheight(mid);
+		const auto midh = mid || midheight(mid);
 		return {{start, midh, c1}, {end, midh, c2}};
 	}
 	else {
@@ -133,7 +133,7 @@ Network::genCurveDef(const Position3D & start, const Position3D & end, float sta
 		const auto c1 = flatStart + sincosf(startDir - half_pi) * radius;
 		const auto c2 = flatEnd + sincosf(endDir - half_pi) * radius;
 		const auto mid = (c1 + c2) / 2.F;
-		const auto midh = mid ^ midheight(mid);
+		const auto midh = mid || midheight(mid);
 		return {{midh, start, c1}, {midh, end, c2}};
 	}
 }
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index 545a728..303f1c8 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -57,7 +57,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end)
 			const auto c1 = flatStart + sincosf(dir + half_pi) * radius;
 			const auto c2 = flatEnd + sincosf(dir2 + half_pi) * radius;
 			const auto mid = (c1 + c2) / 2.F;
-			const auto midh = mid ^ midheight(mid);
+			const auto midh = mid || midheight(mid);
 			addLink<RailLinkCurve>(start, midh, c1);
 			return addLink<RailLinkCurve>(end, midh, c2);
 		}
@@ -66,7 +66,7 @@ RailLinks::addLinksBetween(Position3D start, Position3D end)
 			const auto c1 = flatStart + sincosf(dir - half_pi) * radius;
 			const auto c2 = flatEnd + sincosf(dir2 - half_pi) * radius;
 			const auto mid = (c1 + c2) / 2.F;
-			const auto midh = mid ^ midheight(mid);
+			const auto midh = mid || midheight(mid);
 			addLink<RailLinkCurve>(midh, start, c1);
 			return addLink<RailLinkCurve>(midh, end, c2);
 		}
@@ -133,7 +133,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D &
 		for (auto ei : {1U, 0U}) {
 			const auto trans {glm::translate(ends[ei].node->pos) * e};
 			for (const auto & rcs : railCrossSection) {
-				const Position3D m {(trans * (rcs.first ^ 1))};
+				const Position3D m {(trans * (rcs.first || 1.F))};
 				vertices.emplace_back(m, Position2D {rcs.second, len * static_cast<float>(ei)}, up);
 			}
 		}
@@ -142,7 +142,7 @@ RailLinkStraight::RailLinkStraight(Node::Ptr a, Node::Ptr b, const Position3D &
 }
 
 RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position2D c) :
-	RailLinkCurve(a, b, c ^ a->pos.z, {c ^ 0.F, a->pos, b->pos})
+	RailLinkCurve(a, b, c || a->pos.z, {c || 0.F, a->pos, b->pos})
 {
 }
 
@@ -166,7 +166,7 @@ RailLinkCurve::RailLinkCurve(const Node::Ptr & a, const Node::Ptr & b, Position3
 			const auto t {
 					trans * glm::rotate(half_pi - swing.x, up) * glm::translate(Position3D {radius, 0.F, swing.y})};
 			for (const auto & rcs : railCrossSection) {
-				const Position3D m {(t * (rcs.first ^ 1))};
+				const Position3D m {(t * (rcs.first || 1.F))};
 				vertices.emplace_back(m, Position2D {rcs.second, swing.z}, up);
 			}
 		}
diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp
index 9b23173..5114840 100644
--- a/gfx/followCameraController.cpp
+++ b/gfx/followCameraController.cpp
@@ -24,7 +24,7 @@ FollowCameraController::updateCamera(Camera * camera) const
 			break;
 
 		case Mode::Ride:
-			camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) ^ 0.F);
+			camera->setView(pos + GlobalPosition3D(up * 4.8F), -sincosf(rot.y) || 0.F);
 			break;
 
 		case Mode::ISO:
diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp
index 06e409e..9f40998 100644
--- a/gfx/gl/camera.cpp
+++ b/gfx/gl/camera.cpp
@@ -18,7 +18,7 @@ Camera::unProject(const ScreenRelCoord & mouse) const
 {
 	static constexpr const glm::vec4 screen {0, 0, 1, 1};
 	const auto mouseProjection = glm::lookAt(::origin, forward, up);
-	return {position, glm::normalize(glm::unProject(mouse ^ 1, mouseProjection, projection, screen))};
+	return {position, glm::normalize(glm::unProject(mouse || 1.F, mouseProjection, projection, screen))};
 }
 
 void
diff --git a/lib/maths.cpp b/lib/maths.cpp
index 0c25820..17082d4 100644
--- a/lib/maths.cpp
+++ b/lib/maths.cpp
@@ -9,7 +9,7 @@ glm::mat4
 flat_orientation(const Direction3D & diff)
 {
 	static const auto oneeighty {glm::rotate(pi, up)};
-	const auto flatdiff {glm::normalize(diff.xy() ^ 0.F)};
+	const auto flatdiff {glm::normalize(diff.xy() || 0.F)};
 	auto e {glm::orientation(flatdiff, north)};
 	// Handle if diff is exactly opposite to north
 	return (std::isnan(e[0][0])) ? oneeighty : e;
diff --git a/lib/maths.h b/lib/maths.h
index dd83c4b..f7ff148 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -99,18 +99,6 @@ perspective_divide(glm::vec<4, T, Q> v)
 	return v / v.w;
 }
 
-constexpr inline Position3D
-operator^(const Position2D & v, float z)
-{
-	return {v.x, v.y, z};
-}
-
-constexpr inline glm::vec4
-operator^(const Position3D & v, float w)
-{
-	return {v.x, v.y, v.z, w};
-}
-
 template<glm::length_t L1, glm::length_t L2, typename T, glm::qualifier Q>
 inline constexpr glm::vec<L1 + L2, T, Q>
 operator||(const glm::vec<L1, T, Q> v1, const glm::vec<L2, T, Q> v2)
@@ -125,15 +113,17 @@ operator||(const glm::vec<L, T, Q> v1, const T v2)
 	return {v1, v2};
 }
 
-inline Position3D
-operator%(const Position3D & p, const glm::mat4 & mutation)
+template<glm::length_t L, typename T, glm::qualifier Q>
+inline constexpr glm::vec<L, T, Q>
+operator%(const glm::vec<L, T, Q> & p, const glm::mat<L + 1, L + 1, T, Q> & mutation)
 {
-	const auto p2 = mutation * (p ^ 1);
+	const auto p2 = mutation * (p || T(1));
 	return p2 / p2.w;
 }
 
-inline Position3D
-operator%=(Position3D & p, const glm::mat4 & mutation)
+template<glm::length_t L, typename T, glm::qualifier Q>
+inline constexpr glm::vec<L, T, Q>
+operator%=(glm::vec<L, T, Q> & p, const glm::mat<L + 1, L + 1, T, Q> & mutation)
 {
 	return p = p % mutation;
 }
diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp
index 1f6b510..ef26e81 100644
--- a/ui/manualCameraController.cpp
+++ b/ui/manualCameraController.cpp
@@ -78,6 +78,6 @@ ManualCameraController::render(const UIShader &, const Position &) const
 void
 ManualCameraController::updateCamera(Camera * camera) const
 {
-	const auto forward = glm::normalize(sincosf(direction) ^ -sin(pitch));
-	camera->setView((focus ^ 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward);
+	const auto forward = glm::normalize(sincosf(direction) || -sin(pitch));
+	camera->setView((focus || 0.F) - forward * 3.F * std::pow(dist, 1.3F), forward);
 }
-- 
cgit v1.2.3


From dc672a3488ec1d665fa898ced401e40ebc609bf8 Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Fri, 29 Dec 2023 16:46:48 +0000
Subject: Templatise functions in maths.h using PositionND

---
 lib/maths.cpp       | 72 ---------------------------------------------
 lib/maths.h         | 84 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 test/test-maths.cpp |  3 +-
 3 files changed, 79 insertions(+), 80 deletions(-)

(limited to 'lib')

diff --git a/lib/maths.cpp b/lib/maths.cpp
index 17082d4..68662fc 100644
--- a/lib/maths.cpp
+++ b/lib/maths.cpp
@@ -3,7 +3,6 @@
 #include <glm/glm.hpp>
 #include <glm/gtx/rotate_vector.hpp>
 #include <glm/gtx/transform.hpp>
-#include <stdexcept>
 
 glm::mat4
 flat_orientation(const Direction3D & diff)
@@ -106,77 +105,6 @@ normalize(float ang)
 	return ang;
 }
 
-Arc::Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p) :
-	Arc([&]() -> Arc {
-		const auto diffa = e0p - centre3;
-		const auto diffb = e1p - centre3;
-		const auto anga = vector_yaw(diffa);
-		const auto angb = [&diffb, &anga]() {
-			const auto angb = vector_yaw(diffb);
-			return (angb < anga) ? angb + two_pi : angb;
-		}();
-		return {anga, angb};
-	}())
-{
-}
-
-std::pair<Position2D, bool>
-find_arc_centre(Position2D as, float entrys, Position2D bs, float entrye)
-{
-	if (as == bs) {
-		return {as, false};
-	}
-	return find_arc_centre(as, sincosf(entrys + half_pi), bs, sincosf(entrye - half_pi));
-}
-
-std::pair<Position2D, bool>
-find_arc_centre(Position2D as, Position2D ad, Position2D bs, Position2D bd)
-{
-	const auto det = bd.x * ad.y - bd.y * ad.x;
-	if (det != 0) { // near parallel line will yield noisy results
-		const auto d = bs - as;
-		const auto u = (d.y * bd.x - d.x * bd.y) / det;
-		return {as + ad * u, u < 0};
-	}
-	throw std::runtime_error("no intersection");
-}
-
-std::pair<float, float>
-find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye)
-{
-	const auto getrad = [&](float leftOrRight) {
-		return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight));
-	};
-	return {getrad(-half_pi), getrad(half_pi)};
-}
-
-float
-find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd)
-{
-	// Short name functions for big forula
-	auto sqrt = [](float v) {
-		return std::sqrt(v);
-	};
-
-	// Calculates path across both arcs along the normals... pythagorean theorem... for some known radius r
-	// (2r)^2 = ((m + (X*r)) - (o + (Z*r)))^2 + ((n + (Y*r)) - (p + (W*r)))^2
-	// According to symbolabs.com equation tool, that solves for r to give:
-	// r=(-2 m X+2 X o+2 m Z-2 o Z-2 n Y+2 Y p+2 n W-2 p W-sqrt((2 m X-2 X o-2 m Z+2 o Z+2 n Y-2 Y p-2 n W+2 p W)^(2)-4
-	// (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y W+W^(2)-4) (m^(2)-2 m o+o^(2)+n^(2)-2 n p+p^(2))))/(2 (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y
-	// W+W^(2)-4))
-
-	// These exist cos limitations of online formula rearrangement, and I'm OK with that.
-	const auto &m {start.x}, &n {start.y}, &o {end.x}, &p {end.y};
-	const auto &X {ad.x}, &Y {ad.y}, &Z {bd.x}, &W {bd.y};
-
-	return (2 * m * X - 2 * X * o - 2 * m * Z + 2 * o * Z + 2 * n * Y - 2 * Y * p - 2 * n * W + 2 * p * W
-				   - sqrt(sq(-2 * m * X + 2 * X * o + 2 * m * Z - 2 * o * Z - 2 * n * Y + 2 * Y * p + 2 * n * W
-								  - 2 * p * W)
-						   - (4 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4)
-								   * (sq(m) - 2 * m * o + sq(o) + sq(n) - 2 * n * p + sq(p)))))
-			/ (2 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4));
-}
-
 float
 operator"" _mph(const long double v)
 {
diff --git a/lib/maths.h b/lib/maths.h
index f7ff148..ba8c0e6 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -5,15 +5,17 @@
 #include <glm/glm.hpp>
 #include <glm/gtc/constants.hpp>
 #include <numeric>
+#include <stdexcept>
 #include <utility>
 
 struct Arc : public std::pair<float, float> {
 	using std::pair<float, float>::pair;
 
-	Arc(const Position3D & centre3, const Position3D & e0p, const Position3D & e1p);
+	template<typename T, glm::qualifier Q>
+	Arc(const glm::vec<3, T, Q> & centre3, const glm::vec<3, T, Q> & e0p, const glm::vec<3, T, Q> & e1p);
 
-	float
-	operator[](unsigned int i) const
+	auto
+	operator[](bool i) const
 	{
 		return i ? second : first;
 	}
@@ -136,10 +138,63 @@ arc_length(const Arc & arc)
 
 float normalize(float ang);
 
-std::pair<Position2D, bool> find_arc_centre(Position2D start, float entrys, Position2D end, float entrye);
-std::pair<Position2D, bool> find_arc_centre(Position2D start, Position2D ad, Position2D end, Position2D bd);
-std::pair<float, float> find_arcs_radius(Position2D start, float entrys, Position2D end, float entrye);
-float find_arcs_radius(Position2D start, Position2D ad, Position2D end, Position2D bd);
+template<typename T, glm::qualifier Q>
+std::pair<glm::vec<2, T, Q>, bool>
+find_arc_centre(glm::vec<2, T, Q> start, Rotation2D startDir, glm::vec<2, T, Q> end, Rotation2D endDir)
+{
+	const auto det = endDir.x * startDir.y - endDir.y * startDir.x;
+	if (det != 0) { // near parallel line will yield noisy results
+		const auto d = end - start;
+		const auto u = (d.y * endDir.x - d.x * endDir.y) / det;
+		return {start + startDir * u, u < 0};
+	}
+	throw std::runtime_error("no intersection");
+}
+
+template<typename T, glm::qualifier Q>
+std::pair<glm::vec<2, T, Q>, bool>
+find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye)
+{
+	if (start == end) {
+		return {start, false};
+	}
+	return find_arc_centre(start, sincosf(entrys + half_pi), end, sincosf(entrye - half_pi));
+}
+
+template<typename T, glm::qualifier Q>
+Angle
+find_arcs_radius(glm::vec<2, T, Q> start, Rotation2D ad, glm::vec<2, T, Q> end, Rotation2D bd)
+{
+	using std::sqrt;
+
+	// Calculates path across both arcs along the normals... pythagorean theorem... for some known radius r
+	// (2r)^2 = ((m + (X*r)) - (o + (Z*r)))^2 + ((n + (Y*r)) - (p + (W*r)))^2
+	// According to symbolabs.com equation tool, that solves for r to give:
+	// r=(-2 m X+2 X o+2 m Z-2 o Z-2 n Y+2 Y p+2 n W-2 p W-sqrt((2 m X-2 X o-2 m Z+2 o Z+2 n Y-2 Y p-2 n W+2 p W)^(2)-4
+	// (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y W+W^(2)-4) (m^(2)-2 m o+o^(2)+n^(2)-2 n p+p^(2))))/(2 (X^(2)-2 X Z+Z^(2)+Y^(2)-2 Y
+	// W+W^(2)-4))
+
+	// These exist cos limitations of online formula rearrangement, and I'm OK with that.
+	const auto &m {start.x}, &n {start.y}, &o {end.x}, &p {end.y};
+	const auto &X {ad.x}, &Y {ad.y}, &Z {bd.x}, &W {bd.y};
+
+	return (2 * m * X - 2 * X * o - 2 * m * Z + 2 * o * Z + 2 * n * Y - 2 * Y * p - 2 * n * W + 2 * p * W
+				   - sqrt(sq(-2 * m * X + 2 * X * o + 2 * m * Z - 2 * o * Z - 2 * n * Y + 2 * Y * p + 2 * n * W
+								  - 2 * p * W)
+						   - (4 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4)
+								   * (sq(m) - 2 * m * o + sq(o) + sq(n) - 2 * n * p + sq(p)))))
+			/ (2 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4));
+}
+
+template<typename T, glm::qualifier Q>
+std::pair<Angle, Angle>
+find_arcs_radius(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye)
+{
+	const auto getrad = [&](auto leftOrRight) {
+		return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight));
+	};
+	return {getrad(-half_pi), getrad(half_pi)};
+}
 
 template<typename T>
 auto
@@ -148,6 +203,21 @@ midpoint(const std::pair<T, T> & v)
 	return std::midpoint(v.first, v.second);
 }
 
+template<typename T, glm::qualifier Q>
+Arc::Arc(const glm::vec<3, T, Q> & centre3, const glm::vec<3, T, Q> & e0p, const glm::vec<3, T, Q> & e1p) :
+	Arc([&]() -> Arc {
+		const auto diffa = e0p - centre3;
+		const auto diffb = e1p - centre3;
+		const auto anga = vector_yaw(diffa);
+		const auto angb = [&diffb, &anga]() {
+			const auto angb = vector_yaw(diffb);
+			return (angb < anga) ? angb + two_pi : angb;
+		}();
+		return {anga, angb};
+	}())
+{
+}
+
 // Conversions
 template<typename T>
 inline constexpr auto
diff --git a/test/test-maths.cpp b/test/test-maths.cpp
index 3f8c2a0..ede884d 100644
--- a/test/test-maths.cpp
+++ b/test/test-maths.cpp
@@ -171,7 +171,8 @@ BOOST_DATA_TEST_CASE(test_find_arc_centre,
 
 BOOST_AUTO_TEST_CASE(test_find_arcs_radius)
 {
-	BOOST_CHECK_CLOSE(find_arcs_radius({10.32, 26.71}, {0.4, .92}, {2.92, 22.41}, {-0.89, -0.45}), 2.29, 1);
+	BOOST_CHECK_CLOSE(
+			find_arcs_radius(RelativePosition2D {10.32, 26.71}, {0.4, .92}, {2.92, 22.41}, {-0.89, -0.45}), 2.29, 1);
 }
 
 struct TestLinkStraight : public LinkStraight {
-- 
cgit v1.2.3


From 69e6b7d2d349dcc42d2d415a72181ba729d5a19d Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Mon, 1 Jan 2024 15:53:54 +0000
Subject: Remove more use of legacy types

---
 application/main.cpp          |  9 +++++----
 game/vehicles/railVehicle.cpp |  2 +-
 game/vehicles/railVehicle.h   |  2 +-
 game/vehicles/train.cpp       |  2 +-
 game/vehicles/train.h         |  2 +-
 gfx/gl/bufferedLocation.cpp   |  4 ++--
 gfx/gl/camera.cpp             |  4 ++--
 gfx/gl/shadowMapper.cpp       |  2 +-
 gfx/models/vertex.h           |  9 +++++----
 lib/maths.h                   | 13 ++++++-------
 test/test-maths.cpp           | 20 ++++++++++----------
 11 files changed, 35 insertions(+), 34 deletions(-)

(limited to 'lib')

diff --git a/application/main.cpp b/application/main.cpp
index 600bbe3..adaec9b 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -47,10 +47,11 @@ public:
 
 		{
 			auto rl = world.create<RailLinks>();
-			const Position3D j {-1120000, -1100000, 3000}, k {-1100000, -1000000, 15000}, l {-1000000, -800000, 20000},
-					m {-900000, -600000, 30000}, n {-600000, -500000, 32000}, o {-500000, -800000, 30000},
-					p {-600000, -900000, 25000}, q {-1025000, -1175000, 10000}, r {-925000, -1075000, 10000};
-			const Position3D s {-1100000, -500000, 15000}, t {-1100000, -450000, 15000}, u {-1000000, -400000, 15000};
+			const GlobalPosition3D j {-1120000, -1100000, 3000}, k {-1100000, -1000000, 15000},
+					l {-1000000, -800000, 20000}, m {-900000, -600000, 30000}, n {-600000, -500000, 32000},
+					o {-500000, -800000, 30000}, p {-600000, -900000, 25000}, q {-1025000, -1175000, 10000},
+					r {-925000, -1075000, 10000}, s {-1100000, -500000, 15000}, t {-1100000, -450000, 15000},
+					u {-1000000, -400000, 15000};
 			auto l3 = rl->addLinksBetween(j, k);
 			rl->addLinksBetween(k, l);
 			rl->addLinksBetween(l, m);
diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index 30b615c..7e4b1ee 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -44,7 +44,7 @@ RailVehicle::move(const Train * t, float & trailBy)
 }
 
 bool
-RailVehicle::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const
+RailVehicle::intersectRay(const Ray & ray, BaryPosition * baryPos, float * distance) const
 {
 	constexpr const auto X = 1350.F;
 	const auto Y = this->rvClass->length / 2.F;
diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h
index 20d1ea1..8cbc49d 100644
--- a/game/vehicles/railVehicle.h
+++ b/game/vehicles/railVehicle.h
@@ -17,7 +17,7 @@ public:
 
 	void move(const Train *, float & trailBy);
 
-	[[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override;
+	[[nodiscard]] bool intersectRay(const Ray &, BaryPosition *, float *) const override;
 
 	RailVehicleClassPtr rvClass;
 	using LV = RailVehicleClass::LocationVertex;
diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp
index 4aa24dc..13905a3 100644
--- a/game/vehicles/train.cpp
+++ b/game/vehicles/train.cpp
@@ -20,7 +20,7 @@ Train::getBogiePosition(float linkDist, float dist) const
 }
 
 bool
-Train::intersectRay(const Ray & ray, Position2D * baryPos, float * distance) const
+Train::intersectRay(const Ray & ray, BaryPosition * baryPos, float * distance) const
 {
 	return applyOne(&RailVehicle::intersectRay, ray, baryPos, distance) != end();
 }
diff --git a/game/vehicles/train.h b/game/vehicles/train.h
index 7f0bb99..c77cd23 100644
--- a/game/vehicles/train.h
+++ b/game/vehicles/train.h
@@ -27,7 +27,7 @@ public:
 		return objects.front()->location;
 	}
 
-	[[nodiscard]] bool intersectRay(const Ray &, Position2D *, float *) const override;
+	[[nodiscard]] bool intersectRay(const Ray &, BaryPosition *, float *) const override;
 
 	void tick(TickDuration elapsed) override;
 	void doActivity(Go *, TickDuration) override;
diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp
index d6a63b9..f1bedfe 100644
--- a/gfx/gl/bufferedLocation.cpp
+++ b/gfx/gl/bufferedLocation.cpp
@@ -25,7 +25,7 @@ BufferedLocation::position() const
 	return loc.pos;
 }
 
-Position3D
+Rotation3D
 BufferedLocation::rotation() const
 {
 	return loc.rot;
@@ -41,7 +41,7 @@ BufferedLocation::setPosition(GlobalPosition3D p, bool update)
 }
 
 void
-BufferedLocation::setRotation(Position3D r, bool update)
+BufferedLocation::setRotation(Rotation3D r, bool update)
 {
 	loc.rot = r;
 	if (update) {
diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp
index 9f40998..d362b94 100644
--- a/gfx/gl/camera.cpp
+++ b/gfx/gl/camera.cpp
@@ -17,14 +17,14 @@ Ray
 Camera::unProject(const ScreenRelCoord & mouse) const
 {
 	static constexpr const glm::vec4 screen {0, 0, 1, 1};
-	const auto mouseProjection = glm::lookAt(::origin, forward, up);
+	const auto mouseProjection = glm::lookAt({}, forward, up);
 	return {position, glm::normalize(glm::unProject(mouse || 1.F, mouseProjection, projection, screen))};
 }
 
 void
 Camera::updateView()
 {
-	viewProjection = projection * glm::lookAt(origin, forward, up);
+	viewProjection = projection * glm::lookAt({}, forward, up);
 	inverseViewProjection = glm::inverse(viewProjection);
 }
 
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 6c8400e..1498bb0 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -130,7 +130,7 @@ ShadowMapper::update(const SceneProvider & scene, const Direction3D & dir, const
 	glClear(GL_DEPTH_BUFFER_BIT);
 	glCullFace(GL_FRONT);
 
-	const auto lightViewDir = glm::lookAt(origin, dir, up);
+	const auto lightViewDir = glm::lookAt({}, dir, up);
 	const auto lightViewPoint = camera.getPosition();
 	const auto bandViewExtents = getBandViewExtents(camera, lightViewDir);
 
diff --git a/gfx/models/vertex.h b/gfx/models/vertex.h
index 5635fa1..3c6215f 100644
--- a/gfx/models/vertex.h
+++ b/gfx/models/vertex.h
@@ -6,16 +6,17 @@
 class Vertex {
 public:
 #ifndef __cpp_aggregate_paren_init
-	constexpr Vertex(Position3D pos, TextureRelCoord texCoord, Normal3D normal, RGBA colour = {}, GLuint material = 0) :
-		pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)},
-		material {material}
+	constexpr Vertex(
+			RelativePosition3D pos, TextureRelCoord texCoord, Normal3D normal, RGBA colour = {}, GLuint material = 0) :
+		pos {std::move(pos)},
+		texCoord {std::move(texCoord)}, normal {std::move(normal)}, colour {std::move(colour)}, material {material}
 	{
 	}
 #endif
 
 	bool operator==(const Vertex &) const = default;
 
-	Position3D pos {};
+	RelativePosition3D pos {};
 	TextureRelCoord texCoord {};
 	Normal3D normal {};
 	RGBA colour {};
diff --git a/lib/maths.h b/lib/maths.h
index ba8c0e6..c1bf61a 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -21,13 +21,12 @@ struct Arc : public std::pair<float, float> {
 	}
 };
 
-constexpr const Position3D origin {0, 0, 0};
-constexpr const Position3D up {0, 0, 1};
-constexpr const Position3D down {0, 0, -1};
-constexpr const Position3D north {0, 1, 0};
-constexpr const Position3D south {0, -1, 0};
-constexpr const Position3D east {1, 0, 0};
-constexpr const Position3D west {-1, 0, 0};
+constexpr const RelativePosition3D up {0, 0, 1};
+constexpr const RelativePosition3D down {0, 0, -1};
+constexpr const RelativePosition3D north {0, 1, 0};
+constexpr const RelativePosition3D south {0, -1, 0};
+constexpr const RelativePosition3D east {1, 0, 0};
+constexpr const RelativePosition3D west {-1, 0, 0};
 constexpr auto half_pi {glm::half_pi<float>()};
 constexpr auto quarter_pi {half_pi / 2};
 constexpr auto pi {glm::pi<float>()};
diff --git a/test/test-maths.cpp b/test/test-maths.cpp
index ede884d..b363c17 100644
--- a/test/test-maths.cpp
+++ b/test/test-maths.cpp
@@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(test_find_arcs_radius)
 
 struct TestLinkStraight : public LinkStraight {
 	explicit TestLinkStraight(glm::vec3 v) :
-		Link {{std::make_shared<Node>(origin), vector_yaw(v)}, {std::make_shared<Node>(v), vector_yaw(-v)},
+		Link {{std::make_shared<Node>(Position3D {}), vector_yaw(v)}, {std::make_shared<Node>(v), vector_yaw(-v)},
 				glm::length(v)}
 	{
 	}
@@ -197,7 +197,7 @@ BOOST_DATA_TEST_CASE(straight1,
 	const TestLinkStraight l(v);
 	{
 		const auto p = l.positionAt(0, 0);
-		BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {origin});
+		BOOST_CHECK_EQUAL(p.pos, GlobalPosition3D {});
 		BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angFor, 0));
 	}
 	{
@@ -228,11 +228,11 @@ BOOST_DATA_TEST_CASE(curve1,
 		e1, ctr, angFor, angBack)
 {
 	{ // One-way...
-		const TestLinkCurve l(origin, e1, ctr);
+		const TestLinkCurve l({}, e1, ctr);
 		BOOST_CHECK_EQUAL(l.radius, 1.F);
 		{
 			const auto p = l.positionAt(0, 0);
-			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, RelativePosition3D {});
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angFor, 0));
 		}
 		{
@@ -243,18 +243,18 @@ BOOST_DATA_TEST_CASE(curve1,
 	}
 
 	{ // The other way...
-		const TestLinkCurve l(e1, origin, ctr);
+		const TestLinkCurve l(e1, {}, ctr);
 		BOOST_CHECK_EQUAL(l.radius, 1.F);
 		{
 			const auto p = l.positionAt(0, 0);
-			const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor);
+			const auto angForReversed = normalize(vector_yaw(-e1) * 2 - angFor);
 			BOOST_CHECK_CLOSE_VECI(RelativePosition3D {p.pos}, e1);
 			BOOST_CHECK_CLOSE_VECI(p.rot, glm::vec3(0, angForReversed, 0));
 		}
 		{
 			const auto p = l.positionAt(0, 1);
-			const auto angBackReversed = normalize(vector_yaw(e1 - origin) * 2 - angBack);
-			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, origin);
+			const auto angBackReversed = normalize(vector_yaw(e1) * 2 - angBack);
+			BOOST_CHECK_CLOSE_VEC(RelativePosition3D {p.pos}, Position3D {});
 			BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0));
 		}
 	}
@@ -262,10 +262,10 @@ BOOST_DATA_TEST_CASE(curve1,
 
 BOOST_AUTO_TEST_CASE(camera_clicks)
 {
-	Camera camera {::origin, ::half_pi, 1.25F, 1000, 10000000};
+	Camera camera {{}, ::half_pi, 1.25F, 1000, 10000000};
 	constexpr float centre {0.5F}, right {0.9F}, left {0.1F}, top {1.F}, bottom {0.F};
 	camera.setForward(::north);
-	BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, ::origin);
+	BOOST_CHECK_EQUAL(camera.unProject({centre, centre}).start, RelativePosition3D {});
 	BOOST_CHECK_CLOSE_VEC(camera.unProject({centre, centre}).direction, ::north);
 	BOOST_CHECK_CLOSE_VEC(camera.unProject({left, centre}).direction, glm::normalize(::north + ::west));
 	BOOST_CHECK_CLOSE_VEC(camera.unProject({right, centre}).direction, glm::normalize(::north + ::east));
-- 
cgit v1.2.3